@myned-ai/gsplat-flame-avatar-renderer 1.0.6 → 1.0.7

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 (64) hide show
  1. package/README.md +30 -0
  2. package/dist/gsplat-flame-avatar-renderer.cjs.js +38 -33
  3. package/dist/gsplat-flame-avatar-renderer.cjs.min.js +1 -1
  4. package/dist/gsplat-flame-avatar-renderer.cjs.min.js.map +1 -1
  5. package/dist/gsplat-flame-avatar-renderer.esm.js +38 -33
  6. package/dist/gsplat-flame-avatar-renderer.esm.min.js +1 -1
  7. package/dist/gsplat-flame-avatar-renderer.esm.min.js.map +1 -1
  8. package/package.json +5 -2
  9. package/src/api/index.js +0 -7
  10. package/src/buffers/SplatBuffer.js +0 -1394
  11. package/src/buffers/SplatBufferGenerator.js +0 -41
  12. package/src/buffers/SplatPartitioner.js +0 -110
  13. package/src/buffers/UncompressedSplatArray.js +0 -106
  14. package/src/buffers/index.js +0 -11
  15. package/src/core/SplatGeometry.js +0 -48
  16. package/src/core/SplatMesh.js +0 -2627
  17. package/src/core/SplatScene.js +0 -43
  18. package/src/core/SplatTree.js +0 -200
  19. package/src/core/Viewer.js +0 -2746
  20. package/src/core/index.js +0 -13
  21. package/src/enums/EngineConstants.js +0 -58
  22. package/src/enums/LogLevel.js +0 -13
  23. package/src/enums/RenderMode.js +0 -11
  24. package/src/enums/SceneFormat.js +0 -21
  25. package/src/enums/SceneRevealMode.js +0 -11
  26. package/src/enums/SplatRenderMode.js +0 -10
  27. package/src/enums/index.js +0 -13
  28. package/src/errors/ApplicationError.js +0 -185
  29. package/src/errors/index.js +0 -17
  30. package/src/flame/FlameAnimator.js +0 -496
  31. package/src/flame/FlameConstants.js +0 -21
  32. package/src/flame/FlameTextureManager.js +0 -293
  33. package/src/flame/index.js +0 -22
  34. package/src/flame/utils.js +0 -50
  35. package/src/index.js +0 -39
  36. package/src/loaders/DirectLoadError.js +0 -14
  37. package/src/loaders/INRIAV1PlyParser.js +0 -223
  38. package/src/loaders/PlyLoader.js +0 -519
  39. package/src/loaders/PlyParser.js +0 -19
  40. package/src/loaders/PlyParserUtils.js +0 -311
  41. package/src/loaders/index.js +0 -13
  42. package/src/materials/SplatMaterial.js +0 -1068
  43. package/src/materials/SplatMaterial2D.js +0 -358
  44. package/src/materials/SplatMaterial3D.js +0 -323
  45. package/src/materials/index.js +0 -11
  46. package/src/raycaster/Hit.js +0 -37
  47. package/src/raycaster/Ray.js +0 -123
  48. package/src/raycaster/Raycaster.js +0 -175
  49. package/src/raycaster/index.js +0 -10
  50. package/src/renderer/AnimationManager.js +0 -577
  51. package/src/renderer/AppConstants.js +0 -101
  52. package/src/renderer/GaussianSplatRenderer.js +0 -1146
  53. package/src/renderer/index.js +0 -24
  54. package/src/utils/BlobUrlManager.js +0 -294
  55. package/src/utils/EventEmitter.js +0 -349
  56. package/src/utils/LoaderUtils.js +0 -66
  57. package/src/utils/Logger.js +0 -171
  58. package/src/utils/ObjectPool.js +0 -248
  59. package/src/utils/RenderLoop.js +0 -306
  60. package/src/utils/Util.js +0 -416
  61. package/src/utils/ValidationUtils.js +0 -331
  62. package/src/utils/index.js +0 -18
  63. package/src/worker/SortWorker.js +0 -284
  64. package/src/worker/index.js +0 -8
@@ -1,331 +0,0 @@
1
- /**
2
- * ValidationUtils - Security-focused validation utilities
3
- *
4
- * CRITICAL: All external inputs MUST be validated before use.
5
- * This module provides allowlist-based validation following security best practices.
6
- */
7
-
8
- import { ValidationError } from '../errors/index.js';
9
-
10
- /**
11
- * Allowed URL protocols (allowlist approach)
12
- */
13
- const ALLOWED_PROTOCOLS = Object.freeze(['https:', 'http:', 'blob:', 'data:']);
14
-
15
- /**
16
- * Validate and sanitize a URL
17
- *
18
- * @param {string} url - URL to validate
19
- * @param {string} [baseURL] - Base URL for relative URLs (defaults to window.location.href)
20
- * @returns {string} Sanitized absolute URL
21
- * @throws {ValidationError} If URL is invalid or uses disallowed protocol
22
- */
23
- export function validateUrl(url, baseURL) {
24
- if (typeof url !== 'string' || url.length === 0) {
25
- throw new ValidationError('URL must be a non-empty string', 'url');
26
- }
27
-
28
- let parsed;
29
- try {
30
- // Use base URL if provided, otherwise use window location (browser only)
31
- const base = baseURL || (typeof window !== 'undefined' ? window.location.href : undefined);
32
- parsed = new URL(url, base);
33
- } catch (error) {
34
- throw new ValidationError(
35
- `Invalid URL format: ${url}`,
36
- 'url',
37
- error
38
- );
39
- }
40
-
41
- // Validate protocol against allowlist
42
- if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {
43
- throw new ValidationError(
44
- `Disallowed protocol: ${parsed.protocol}. Allowed protocols: ${ALLOWED_PROTOCOLS.join(', ')}`,
45
- 'url.protocol'
46
- );
47
- }
48
-
49
- return parsed.href;
50
- }
51
-
52
- /**
53
- * Validate asset path to prevent path traversal attacks
54
- *
55
- * @param {string} path - File path to validate
56
- * @returns {string} Validated path
57
- * @throws {ValidationError} If path contains traversal sequences
58
- */
59
- export function validateAssetPath(path) {
60
- if (typeof path !== 'string' || path.length === 0) {
61
- throw new ValidationError('Asset path must be a non-empty string', 'path');
62
- }
63
-
64
- // Check for path traversal sequences
65
- const dangerousPatterns = ['../', '..\\', '%2e%2e/', '%2e%2e\\'];
66
- const normalizedPath = path.toLowerCase();
67
-
68
- for (const pattern of dangerousPatterns) {
69
- if (normalizedPath.includes(pattern)) {
70
- throw new ValidationError(
71
- `Path traversal detected in asset path: ${path}`,
72
- 'path'
73
- );
74
- }
75
- }
76
-
77
- return path;
78
- }
79
-
80
- /**
81
- * Validate file extension against allowlist
82
- *
83
- * @param {string} filename - Filename to validate
84
- * @param {string[]} allowedExtensions - Array of allowed extensions (e.g., ['.ply', '.glb'])
85
- * @returns {string} Validated filename
86
- * @throws {ValidationError} If extension is not allowed
87
- */
88
- export function validateFileExtension(filename, allowedExtensions) {
89
- if (typeof filename !== 'string' || filename.length === 0) {
90
- throw new ValidationError('Filename must be a non-empty string', 'filename');
91
- }
92
-
93
- if (!Array.isArray(allowedExtensions) || allowedExtensions.length === 0) {
94
- throw new ValidationError(
95
- 'allowedExtensions must be a non-empty array',
96
- 'allowedExtensions'
97
- );
98
- }
99
-
100
- const extension = filename.slice(filename.lastIndexOf('.')).toLowerCase();
101
- const normalizedAllowed = allowedExtensions.map(ext => ext.toLowerCase());
102
-
103
- if (!normalizedAllowed.includes(extension)) {
104
- throw new ValidationError(
105
- `File extension ${extension} not allowed. Allowed: ${allowedExtensions.join(', ')}`,
106
- 'filename'
107
- );
108
- }
109
-
110
- return filename;
111
- }
112
-
113
- /**
114
- * Validate numeric value is within range
115
- *
116
- * @param {number} value - Value to validate
117
- * @param {number} min - Minimum allowed value (inclusive)
118
- * @param {number} max - Maximum allowed value (inclusive)
119
- * @param {string} fieldName - Name of field for error messages
120
- * @returns {number} Validated value
121
- * @throws {ValidationError} If value is not a number or out of range
122
- */
123
- export function validateNumberInRange(value, min, max, fieldName) {
124
- if (typeof value !== 'number' || isNaN(value)) {
125
- throw new ValidationError(
126
- `${fieldName} must be a valid number`,
127
- fieldName
128
- );
129
- }
130
-
131
- if (value < min || value > max) {
132
- throw new ValidationError(
133
- `${fieldName} must be between ${min} and ${max}, got ${value}`,
134
- fieldName
135
- );
136
- }
137
-
138
- return value;
139
- }
140
-
141
- /**
142
- * Validate integer value
143
- *
144
- * @param {number} value - Value to validate
145
- * @param {string} fieldName - Name of field for error messages
146
- * @returns {number} Validated integer
147
- * @throws {ValidationError} If value is not an integer
148
- */
149
- export function validateInteger(value, fieldName) {
150
- if (typeof value !== 'number' || !Number.isInteger(value)) {
151
- throw new ValidationError(
152
- `${fieldName} must be an integer`,
153
- fieldName
154
- );
155
- }
156
-
157
- return value;
158
- }
159
-
160
- /**
161
- * Validate positive integer
162
- *
163
- * @param {number} value - Value to validate
164
- * @param {string} fieldName - Name of field for error messages
165
- * @returns {number} Validated positive integer
166
- * @throws {ValidationError} If value is not a positive integer
167
- */
168
- export function validatePositiveInteger(value, fieldName) {
169
- validateInteger(value, fieldName);
170
-
171
- if (value <= 0) {
172
- throw new ValidationError(
173
- `${fieldName} must be positive, got ${value}`,
174
- fieldName
175
- );
176
- }
177
-
178
- return value;
179
- }
180
-
181
- /**
182
- * Validate object has required properties
183
- *
184
- * @param {object} obj - Object to validate
185
- * @param {string[]} requiredProps - Array of required property names
186
- * @param {string} objectName - Name of object for error messages
187
- * @returns {object} Validated object
188
- * @throws {ValidationError} If object is invalid or missing required properties
189
- */
190
- export function validateRequiredProperties(obj, requiredProps, objectName) {
191
- if (obj === null || typeof obj !== 'object') {
192
- throw new ValidationError(
193
- `${objectName} must be an object`,
194
- objectName
195
- );
196
- }
197
-
198
- for (const prop of requiredProps) {
199
- if (!(prop in obj) || obj[prop] === undefined) {
200
- throw new ValidationError(
201
- `${objectName} missing required property: ${prop}`,
202
- `${objectName}.${prop}`
203
- );
204
- }
205
- }
206
-
207
- return obj;
208
- }
209
-
210
- /**
211
- * Validate array buffer
212
- *
213
- * @param {ArrayBuffer} buffer - Buffer to validate
214
- * @param {string} fieldName - Name of field for error messages
215
- * @param {number} [minSize=0] - Minimum size in bytes
216
- * @returns {ArrayBuffer} Validated buffer
217
- * @throws {ValidationError} If buffer is invalid or too small
218
- */
219
- export function validateArrayBuffer(buffer, fieldName, minSize = 0) {
220
- if (!(buffer instanceof ArrayBuffer)) {
221
- throw new ValidationError(
222
- `${fieldName} must be an ArrayBuffer`,
223
- fieldName
224
- );
225
- }
226
-
227
- if (buffer.byteLength < minSize) {
228
- throw new ValidationError(
229
- `${fieldName} must be at least ${minSize} bytes, got ${buffer.byteLength}`,
230
- fieldName
231
- );
232
- }
233
-
234
- return buffer;
235
- }
236
-
237
- /**
238
- * Validate enum value against allowed values
239
- *
240
- * @param {*} value - Value to validate
241
- * @param {Array} allowedValues - Array of allowed values
242
- * @param {string} fieldName - Name of field for error messages
243
- * @returns {*} Validated value
244
- * @throws {ValidationError} If value is not in allowed values
245
- */
246
- export function validateEnum(value, allowedValues, fieldName) {
247
- if (!allowedValues.includes(value)) {
248
- throw new ValidationError(
249
- `${fieldName} must be one of: ${allowedValues.join(', ')}. Got: ${value}`,
250
- fieldName
251
- );
252
- }
253
-
254
- return value;
255
- }
256
-
257
- /**
258
- * Validate callback function
259
- *
260
- * @param {Function} callback - Callback to validate
261
- * @param {string} fieldName - Name of field for error messages
262
- * @param {boolean} [required=true] - Whether callback is required
263
- * @returns {Function|null} Validated callback or null if not required and not provided
264
- * @throws {ValidationError} If callback is required but not a function
265
- */
266
- export function validateCallback(callback, fieldName, required = true) {
267
- if (callback === null || callback === undefined) {
268
- if (required) {
269
- throw new ValidationError(
270
- `${fieldName} is required`,
271
- fieldName
272
- );
273
- }
274
- return null;
275
- }
276
-
277
- if (typeof callback !== 'function') {
278
- throw new ValidationError(
279
- `${fieldName} must be a function`,
280
- fieldName
281
- );
282
- }
283
-
284
- return callback;
285
- }
286
-
287
- /**
288
- * Validate hex color string
289
- *
290
- * @param {string} value - Color string to validate
291
- * @param {string} fieldName - Name of field for error messages
292
- * @returns {string} Validated color string
293
- * @throws {ValidationError} If color format is invalid
294
- */
295
- export function validateHexColor(value, fieldName) {
296
- if (typeof value !== 'string') {
297
- throw new ValidationError(
298
- `${fieldName} must be a string`,
299
- fieldName
300
- );
301
- }
302
-
303
- const hexColorRegex = /^(#|0x)[0-9A-Fa-f]{6}$/i;
304
- if (!hexColorRegex.test(value)) {
305
- throw new ValidationError(
306
- `${fieldName} must be a valid hex color (e.g., #FFFFFF or 0xFFFFFF)`,
307
- fieldName
308
- );
309
- }
310
-
311
- return value;
312
- }
313
-
314
- /**
315
- * Validate DOM element
316
- *
317
- * @param {HTMLElement} element - Element to validate
318
- * @param {string} fieldName - Name of field for error messages
319
- * @returns {HTMLElement} Validated element
320
- * @throws {ValidationError} If element is not a valid DOM element
321
- */
322
- export function validateDOMElement(element, fieldName) {
323
- if (typeof HTMLElement !== 'undefined' && !(element instanceof HTMLElement)) {
324
- throw new ValidationError(
325
- `${fieldName} must be a valid HTML element`,
326
- fieldName
327
- );
328
- }
329
-
330
- return element;
331
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * gsplat-flame-avatar - Utils Module
3
- * Shared utility functions.
4
- *
5
- * Derived from @mkkellogg/gaussian-splats-3d (MIT License)
6
- */
7
-
8
- // Original utilities
9
- export * from './LoaderUtils.js';
10
- export * from './Util.js';
11
-
12
- // New refactored utilities
13
- export * from './ValidationUtils.js';
14
- export * from './Logger.js';
15
- export * from './ObjectPool.js';
16
- export * from './BlobUrlManager.js';
17
- export * from './RenderLoop.js';
18
- export * from './EventEmitter.js';
@@ -1,284 +0,0 @@
1
- /**
2
- * SortWorker
3
- *
4
- * Derived from @mkkellogg/gaussian-splats-3d (MIT License)
5
- * https://github.com/mkkellogg/GaussianSplats3D
6
- *
7
- * Handles GPU-based sorting using WebAssembly
8
- */
9
-
10
- import { isIOS, getIOSSemever } from '../utils/Util.js';
11
- import { Constants } from '../enums/EngineConstants.js';
12
-
13
- // Base64 encoded WASM modules for sorting
14
- const SorterWasm = "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";
15
-
16
- const SorterWasmNoSIMD = "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";
17
-
18
- const SorterWasmNonShared = "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";
19
-
20
- const SorterWasmNoSIMDNonShared = "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";
21
-
22
- /**
23
- * Sort worker function that runs in a Web Worker
24
- * Handles the actual sorting logic using WebAssembly
25
- */
26
- function sortWorker(self) {
27
-
28
- let wasmInstance;
29
- let wasmMemory;
30
- let useSharedMemory;
31
- let integerBasedSort;
32
- let dynamicMode;
33
- let splatCount;
34
- let indexesToSortOffset;
35
- let sortedIndexesOffset;
36
- let sceneIndexesOffset;
37
- let transformsOffset;
38
- let precomputedDistancesOffset;
39
- let mappedDistancesOffset;
40
- let frequenciesOffset;
41
- let centersOffset;
42
- let modelViewProjOffset;
43
- let countsZero;
44
- let sortedIndexesOut;
45
- let distanceMapRange;
46
- let uploadedSplatCount;
47
- let Constants;
48
-
49
- function sort(splatSortCount, splatRenderCount, modelViewProj,
50
- usePrecomputedDistances, copyIndexesToSort, copyPrecomputedDistances, copyTransforms) {
51
- const sortStartTime = performance.now();
52
-
53
- if (!useSharedMemory) {
54
- const indexesToSort = new Uint32Array(wasmMemory, indexesToSortOffset, copyIndexesToSort.byteLength / Constants.BytesPerInt);
55
- indexesToSort.set(copyIndexesToSort);
56
- const transforms = new Float32Array(wasmMemory, transformsOffset, copyTransforms.byteLength / Constants.BytesPerFloat);
57
- transforms.set(copyTransforms);
58
- if (usePrecomputedDistances) {
59
- let precomputedDistances;
60
- if (integerBasedSort) {
61
- precomputedDistances = new Int32Array(wasmMemory, precomputedDistancesOffset,
62
- copyPrecomputedDistances.byteLength / Constants.BytesPerInt);
63
- } else {
64
- precomputedDistances = new Float32Array(wasmMemory, precomputedDistancesOffset,
65
- copyPrecomputedDistances.byteLength / Constants.BytesPerFloat);
66
- }
67
- precomputedDistances.set(copyPrecomputedDistances);
68
- }
69
- }
70
-
71
- if (!countsZero) countsZero = new Uint32Array(distanceMapRange);
72
- new Float32Array(wasmMemory, modelViewProjOffset, 16).set(modelViewProj);
73
- new Uint32Array(wasmMemory, frequenciesOffset, distanceMapRange).set(countsZero);
74
- wasmInstance.exports.sortIndexes(indexesToSortOffset, centersOffset, precomputedDistancesOffset,
75
- mappedDistancesOffset, frequenciesOffset, modelViewProjOffset,
76
- sortedIndexesOffset, sceneIndexesOffset, transformsOffset, distanceMapRange,
77
- splatSortCount, splatRenderCount, splatCount, usePrecomputedDistances, integerBasedSort,
78
- dynamicMode);
79
-
80
- const sortMessage = {
81
- 'sortDone': true,
82
- 'splatSortCount': splatSortCount,
83
- 'splatRenderCount': splatRenderCount,
84
- 'sortTime': 0
85
- };
86
- if (!useSharedMemory) {
87
- const sortedIndexes = new Uint32Array(wasmMemory, sortedIndexesOffset, splatRenderCount);
88
- if (!sortedIndexesOut || sortedIndexesOut.length < splatRenderCount) {
89
- sortedIndexesOut = new Uint32Array(splatRenderCount);
90
- }
91
- sortedIndexesOut.set(sortedIndexes);
92
- sortMessage.sortedIndexes = sortedIndexesOut;
93
- }
94
- const sortEndTime = performance.now();
95
-
96
- sortMessage.sortTime = sortEndTime - sortStartTime;
97
-
98
- self.postMessage(sortMessage);
99
- }
100
-
101
- self.onmessage = (e) => {
102
- if (e.data.centers) {
103
- let centers = e.data.centers;
104
- let sceneIndexes = e.data.sceneIndexes;
105
- if (integerBasedSort) {
106
- new Int32Array(wasmMemory, centersOffset + e.data.range.from * Constants.BytesPerInt * 4,
107
- e.data.range.count * 4).set(new Int32Array(centers));
108
- } else {
109
- new Float32Array(wasmMemory, centersOffset + e.data.range.from * Constants.BytesPerFloat * 4,
110
- e.data.range.count * 4).set(new Float32Array(centers));
111
- }
112
- if (dynamicMode) {
113
- new Uint32Array(wasmMemory, sceneIndexesOffset + e.data.range.from * 4,
114
- e.data.range.count).set(new Uint32Array(sceneIndexes));
115
- }
116
- uploadedSplatCount = e.data.range.from + e.data.range.count;
117
- } else if (e.data.sort) {
118
- const renderCount = Math.min(e.data.sort.splatRenderCount || 0, uploadedSplatCount);
119
- const sortCount = Math.min(e.data.sort.splatSortCount || 0, uploadedSplatCount);
120
- const usePrecomputedDistances = e.data.sort.usePrecomputedDistances;
121
-
122
- let copyIndexesToSort;
123
- let copyPrecomputedDistances;
124
- let copyTransforms;
125
- if (!useSharedMemory) {
126
- copyIndexesToSort = e.data.sort.indexesToSort;
127
- copyTransforms = e.data.sort.transforms;
128
- if (usePrecomputedDistances) copyPrecomputedDistances = e.data.sort.precomputedDistances;
129
- }
130
- sort(sortCount, renderCount, e.data.sort.modelViewProj, usePrecomputedDistances,
131
- copyIndexesToSort, copyPrecomputedDistances, copyTransforms);
132
- } else if (e.data.init) {
133
- // Yep, this is super hacky and gross :(
134
- Constants = e.data.init.Constants;
135
-
136
- splatCount = e.data.init.splatCount;
137
- useSharedMemory = e.data.init.useSharedMemory;
138
- integerBasedSort = e.data.init.integerBasedSort;
139
- dynamicMode = e.data.init.dynamicMode;
140
- distanceMapRange = e.data.init.distanceMapRange;
141
- uploadedSplatCount = 0;
142
-
143
- const CENTERS_BYTES_PER_ENTRY = integerBasedSort ? (Constants.BytesPerInt * 4) : (Constants.BytesPerFloat * 4);
144
-
145
- const sorterWasmBytes = new Uint8Array(e.data.init.sorterWasmBytes);
146
-
147
- const matrixSize = 16 * Constants.BytesPerFloat;
148
- const memoryRequiredForIndexesToSort = splatCount * Constants.BytesPerInt;
149
- const memoryRequiredForCenters = splatCount * CENTERS_BYTES_PER_ENTRY;
150
- const memoryRequiredForModelViewProjectionMatrix = matrixSize;
151
- const memoryRequiredForPrecomputedDistances = integerBasedSort ?
152
- (splatCount * Constants.BytesPerInt) : (splatCount * Constants.BytesPerFloat);
153
- const memoryRequiredForMappedDistances = splatCount * Constants.BytesPerInt;
154
- const memoryRequiredForSortedIndexes = splatCount * Constants.BytesPerInt;
155
- const memoryRequiredForIntermediateSortBuffers = integerBasedSort ? (distanceMapRange * Constants.BytesPerInt * 2) :
156
- (distanceMapRange * Constants.BytesPerFloat * 2);
157
- const memoryRequiredforTransformIndexes = dynamicMode ? (splatCount * Constants.BytesPerInt) : 0;
158
- const memoryRequiredforTransforms = dynamicMode ? (Constants.MaxScenes * matrixSize) : 0;
159
- const extraMemory = Constants.MemoryPageSize * 32;
160
-
161
- const totalRequiredMemory = memoryRequiredForIndexesToSort +
162
- memoryRequiredForCenters +
163
- memoryRequiredForModelViewProjectionMatrix +
164
- memoryRequiredForPrecomputedDistances +
165
- memoryRequiredForMappedDistances +
166
- memoryRequiredForIntermediateSortBuffers +
167
- memoryRequiredForSortedIndexes +
168
- memoryRequiredforTransformIndexes +
169
- memoryRequiredforTransforms +
170
- extraMemory;
171
- const totalPagesRequired = Math.floor(totalRequiredMemory / Constants.MemoryPageSize ) + 1;
172
- const sorterWasmImport = {
173
- module: {},
174
- env: {
175
- memory: new WebAssembly.Memory({
176
- initial: totalPagesRequired,
177
- maximum: totalPagesRequired,
178
- shared: true,
179
- }),
180
- }
181
- };
182
- WebAssembly.compile(sorterWasmBytes)
183
- .then((wasmModule) => {
184
- return WebAssembly.instantiate(wasmModule, sorterWasmImport);
185
- })
186
- .then((instance) => {
187
- wasmInstance = instance;
188
- indexesToSortOffset = 0;
189
- centersOffset = indexesToSortOffset + memoryRequiredForIndexesToSort;
190
- modelViewProjOffset = centersOffset + memoryRequiredForCenters;
191
- precomputedDistancesOffset = modelViewProjOffset + memoryRequiredForModelViewProjectionMatrix;
192
- mappedDistancesOffset = precomputedDistancesOffset + memoryRequiredForPrecomputedDistances;
193
- frequenciesOffset = mappedDistancesOffset + memoryRequiredForMappedDistances;
194
- sortedIndexesOffset = frequenciesOffset + memoryRequiredForIntermediateSortBuffers;
195
- sceneIndexesOffset = sortedIndexesOffset + memoryRequiredForSortedIndexes;
196
- transformsOffset = sceneIndexesOffset + memoryRequiredforTransformIndexes;
197
- wasmMemory = sorterWasmImport.env.memory.buffer;
198
- if (useSharedMemory) {
199
- self.postMessage({
200
- 'sortSetupPhase1Complete': true,
201
- 'indexesToSortBuffer': wasmMemory,
202
- 'indexesToSortOffset': indexesToSortOffset,
203
- 'sortedIndexesBuffer': wasmMemory,
204
- 'sortedIndexesOffset': sortedIndexesOffset,
205
- 'precomputedDistancesBuffer': wasmMemory,
206
- 'precomputedDistancesOffset': precomputedDistancesOffset,
207
- 'transformsBuffer': wasmMemory,
208
- 'transformsOffset': transformsOffset
209
- });
210
- } else {
211
- self.postMessage({
212
- 'sortSetupPhase1Complete': true
213
- });
214
- }
215
- });
216
- }
217
- };
218
- }
219
-
220
- /**
221
- * Creates a sort worker for GPU-based sorting
222
- * @param {number} splatCount - Number of splats to sort
223
- * @param {boolean} useSharedMemory - Whether to use shared memory
224
- * @param {boolean} enableSIMDInSort - Whether to enable SIMD instructions
225
- * @param {boolean} integerBasedSort - Whether to use integer-based sorting
226
- * @param {boolean} dynamicMode - Whether dynamic mode is enabled
227
- * @param {number} splatSortDistanceMapPrecision - Precision for distance map
228
- * @returns {Worker} The created sort worker
229
- */
230
- export function createSortWorker(splatCount, useSharedMemory, enableSIMDInSort, integerBasedSort, dynamicMode,
231
- splatSortDistanceMapPrecision = Constants.DefaultSplatSortDistanceMapPrecision) {
232
- const worker = new Worker(
233
- URL.createObjectURL(
234
- new Blob(['(', sortWorker.toString(), ')(self)'], {
235
- type: 'application/javascript',
236
- }),
237
- ),
238
- );
239
-
240
- let sourceWasm = SorterWasm;
241
-
242
- // iOS makes choosing the right WebAssembly configuration tricky :(
243
- const iOSSemVer = isIOS() ? getIOSSemever() : null;
244
- if (!enableSIMDInSort && !useSharedMemory) {
245
- sourceWasm = SorterWasmNoSIMD;
246
- // Testing on various devices has shown that even when shared memory is disabled, the WASM module with shared
247
- // memory can still be used most of the time -- the exception seems to be iOS devices below 16.4
248
- if (iOSSemVer && iOSSemVer.major <= 16 && iOSSemVer.minor < 4) {
249
- sourceWasm = SorterWasmNoSIMDNonShared;
250
- }
251
- } else if (!enableSIMDInSort) {
252
- sourceWasm = SorterWasmNoSIMD;
253
- } else if (!useSharedMemory) {
254
- // Same issue with shared memory as above on iOS devices
255
- if (iOSSemVer && iOSSemVer.major <= 16 && iOSSemVer.minor < 4) {
256
- sourceWasm = SorterWasmNonShared;
257
- }
258
- }
259
-
260
- const sorterWasmBinaryString = atob(sourceWasm);
261
- const sorterWasmBytes = new Uint8Array(sorterWasmBinaryString.length);
262
- for (let i = 0; i < sorterWasmBinaryString.length; i++) {
263
- sorterWasmBytes[i] = sorterWasmBinaryString.charCodeAt(i);
264
- }
265
-
266
- worker.postMessage({
267
- 'init': {
268
- 'sorterWasmBytes': sorterWasmBytes.buffer,
269
- 'splatCount': splatCount,
270
- 'useSharedMemory': useSharedMemory,
271
- 'integerBasedSort': integerBasedSort,
272
- 'dynamicMode': dynamicMode,
273
- 'distanceMapRange': 1 << splatSortDistanceMapPrecision,
274
- // Super hacky
275
- 'Constants': {
276
- 'BytesPerFloat': Constants.BytesPerFloat,
277
- 'BytesPerInt': Constants.BytesPerInt,
278
- 'MemoryPageSize': Constants.MemoryPageSize,
279
- 'MaxScenes': Constants.MaxScenes
280
- }
281
- }
282
- });
283
- return worker;
284
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * gsplat-flame-avatar - Worker Module
3
- * WebAssembly-based sorting for depth ordering.
4
- *
5
- * Derived from @mkkellogg/gaussian-splats-3d (MIT License)
6
- */
7
-
8
- export { createSortWorker } from './SortWorker.js';