@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.
- package/README.md +30 -0
- package/dist/gsplat-flame-avatar-renderer.cjs.js +38 -33
- package/dist/gsplat-flame-avatar-renderer.cjs.min.js +1 -1
- package/dist/gsplat-flame-avatar-renderer.cjs.min.js.map +1 -1
- package/dist/gsplat-flame-avatar-renderer.esm.js +38 -33
- package/dist/gsplat-flame-avatar-renderer.esm.min.js +1 -1
- package/dist/gsplat-flame-avatar-renderer.esm.min.js.map +1 -1
- package/package.json +5 -2
- package/src/api/index.js +0 -7
- package/src/buffers/SplatBuffer.js +0 -1394
- package/src/buffers/SplatBufferGenerator.js +0 -41
- package/src/buffers/SplatPartitioner.js +0 -110
- package/src/buffers/UncompressedSplatArray.js +0 -106
- package/src/buffers/index.js +0 -11
- package/src/core/SplatGeometry.js +0 -48
- package/src/core/SplatMesh.js +0 -2627
- package/src/core/SplatScene.js +0 -43
- package/src/core/SplatTree.js +0 -200
- package/src/core/Viewer.js +0 -2746
- package/src/core/index.js +0 -13
- package/src/enums/EngineConstants.js +0 -58
- package/src/enums/LogLevel.js +0 -13
- package/src/enums/RenderMode.js +0 -11
- package/src/enums/SceneFormat.js +0 -21
- package/src/enums/SceneRevealMode.js +0 -11
- package/src/enums/SplatRenderMode.js +0 -10
- package/src/enums/index.js +0 -13
- package/src/errors/ApplicationError.js +0 -185
- package/src/errors/index.js +0 -17
- package/src/flame/FlameAnimator.js +0 -496
- package/src/flame/FlameConstants.js +0 -21
- package/src/flame/FlameTextureManager.js +0 -293
- package/src/flame/index.js +0 -22
- package/src/flame/utils.js +0 -50
- package/src/index.js +0 -39
- package/src/loaders/DirectLoadError.js +0 -14
- package/src/loaders/INRIAV1PlyParser.js +0 -223
- package/src/loaders/PlyLoader.js +0 -519
- package/src/loaders/PlyParser.js +0 -19
- package/src/loaders/PlyParserUtils.js +0 -311
- package/src/loaders/index.js +0 -13
- package/src/materials/SplatMaterial.js +0 -1068
- package/src/materials/SplatMaterial2D.js +0 -358
- package/src/materials/SplatMaterial3D.js +0 -323
- package/src/materials/index.js +0 -11
- package/src/raycaster/Hit.js +0 -37
- package/src/raycaster/Ray.js +0 -123
- package/src/raycaster/Raycaster.js +0 -175
- package/src/raycaster/index.js +0 -10
- package/src/renderer/AnimationManager.js +0 -577
- package/src/renderer/AppConstants.js +0 -101
- package/src/renderer/GaussianSplatRenderer.js +0 -1146
- package/src/renderer/index.js +0 -24
- package/src/utils/BlobUrlManager.js +0 -294
- package/src/utils/EventEmitter.js +0 -349
- package/src/utils/LoaderUtils.js +0 -66
- package/src/utils/Logger.js +0 -171
- package/src/utils/ObjectPool.js +0 -248
- package/src/utils/RenderLoop.js +0 -306
- package/src/utils/Util.js +0 -416
- package/src/utils/ValidationUtils.js +0 -331
- package/src/utils/index.js +0 -18
- package/src/worker/SortWorker.js +0 -284
- 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
|
-
}
|
package/src/utils/index.js
DELETED
|
@@ -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';
|
package/src/worker/SortWorker.js
DELETED
|
@@ -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
|
-
}
|