@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,306 +0,0 @@
1
- /**
2
- * RenderLoop - Frame-independent animation loop with budget management
3
- *
4
- * Provides a robust requestAnimationFrame loop with:
5
- * - Delta time calculation for frame-independent updates
6
- * - Frame budget management to prevent frame drops
7
- * - Deferred task execution
8
- * - Performance monitoring
9
- */
10
-
11
- import { getLogger } from './Logger.js';
12
-
13
- const logger = getLogger('RenderLoop');
14
-
15
- /**
16
- * RenderLoop - Manages animation frame loop
17
- */
18
- export class RenderLoop {
19
- /**
20
- * Create a RenderLoop
21
- * @param {Function} updateFn - Update function called each frame with deltaTime
22
- * @param {Function} renderFn - Render function called each frame
23
- * @param {object} [options] - Configuration options
24
- * @param {number} [options.targetFps=60] - Target frames per second
25
- * @param {number} [options.maxDeltaTime=0.1] - Maximum delta time in seconds (prevents spiral of death)
26
- */
27
- constructor(updateFn, renderFn, options = {}) {
28
- this._update = updateFn;
29
- this._render = renderFn;
30
-
31
- this._targetFps = options.targetFps || 60;
32
- this._maxDeltaTime = options.maxDeltaTime || 0.1; // 100ms max
33
- this._frameBudget = 1000 / this._targetFps; // ms per frame
34
-
35
- this._running = false;
36
- this._rafId = null;
37
- this._lastTime = 0;
38
- this._frameCount = 0;
39
- this._deferredTasks = [];
40
-
41
- // Performance tracking
42
- this._fpsHistory = [];
43
- this._fpsHistorySize = 60; // Track last 60 frames
44
- this._lastFpsUpdate = 0;
45
- this._currentFps = 0;
46
- }
47
-
48
- /**
49
- * Start the render loop
50
- */
51
- start() {
52
- if (this._running) {
53
- logger.warn('RenderLoop already running');
54
- return;
55
- }
56
-
57
- this._running = true;
58
- this._lastTime = performance.now();
59
- this._frameCount = 0;
60
- logger.info('RenderLoop started');
61
-
62
- this._tick();
63
- }
64
-
65
- /**
66
- * Stop the render loop
67
- */
68
- stop() {
69
- if (!this._running) {
70
- return;
71
- }
72
-
73
- this._running = false;
74
-
75
- if (this._rafId !== null) {
76
- cancelAnimationFrame(this._rafId);
77
- this._rafId = null;
78
- }
79
-
80
- logger.info(`RenderLoop stopped after ${this._frameCount} frames`);
81
- }
82
-
83
- /**
84
- * Main loop tick
85
- * @private
86
- */
87
- _tick = () => {
88
- if (!this._running) {
89
- return;
90
- }
91
-
92
- const frameStart = performance.now();
93
- const rawDeltaTime = (frameStart - this._lastTime) / 1000; // Convert to seconds
94
-
95
- // Clamp delta time to prevent spiral of death
96
- const deltaTime = Math.min(rawDeltaTime, this._maxDeltaTime);
97
-
98
- this._lastTime = frameStart;
99
- this._frameCount++;
100
-
101
- try {
102
- // Update logic
103
- this._update(deltaTime);
104
-
105
- // Render
106
- this._render();
107
-
108
- // Process deferred tasks if time permits
109
- const frameElapsed = performance.now() - frameStart;
110
- const remainingTime = this._frameBudget - frameElapsed;
111
-
112
- if (remainingTime > 1 && this._deferredTasks.length > 0) {
113
- this._processDeferredTasks(remainingTime - 1); // Leave 1ms margin
114
- }
115
-
116
- // Update FPS tracking
117
- this._updateFpsTracking(performance.now() - frameStart);
118
-
119
- } catch (error) {
120
- logger.error('Error in render loop:', error);
121
- // Continue loop despite error
122
- }
123
-
124
- // Schedule next frame
125
- this._rafId = requestAnimationFrame(this._tick);
126
- };
127
-
128
- /**
129
- * Update FPS tracking
130
- * @private
131
- * @param {number} frameTime - Time taken for this frame in ms
132
- */
133
- _updateFpsTracking(frameTime) {
134
- this._fpsHistory.push(1000 / frameTime);
135
-
136
- if (this._fpsHistory.length > this._fpsHistorySize) {
137
- this._fpsHistory.shift();
138
- }
139
-
140
- // Update FPS every second
141
- const now = performance.now();
142
- if (now - this._lastFpsUpdate > 1000) {
143
- this._currentFps = this._fpsHistory.reduce((a, b) => a + b, 0) / this._fpsHistory.length;
144
- this._lastFpsUpdate = now;
145
- }
146
- }
147
-
148
- /**
149
- * Process deferred tasks within time budget
150
- * @private
151
- * @param {number} maxTime - Maximum time in ms to spend on tasks
152
- */
153
- _processDeferredTasks(maxTime) {
154
- const startTime = performance.now();
155
-
156
- while (this._deferredTasks.length > 0) {
157
- if (performance.now() - startTime >= maxTime) {
158
- break;
159
- }
160
-
161
- const task = this._deferredTasks.shift();
162
-
163
- try {
164
- task.fn();
165
- } catch (error) {
166
- logger.error(`Error in deferred task: ${task.label}`, error);
167
- }
168
- }
169
- }
170
-
171
- /**
172
- * Execute task if within frame budget, otherwise defer
173
- *
174
- * @param {Function} task - Task function to execute
175
- * @param {number} [priority=0] - Task priority (higher = more important)
176
- * @param {string} [label=''] - Task label for debugging
177
- */
178
- executeOrDefer(task, priority = 0, label = '') {
179
- const frameElapsed = performance.now() - this._lastTime;
180
-
181
- if (frameElapsed < this._frameBudget * 0.8) {
182
- // Within budget, execute now
183
- task();
184
- } else {
185
- // Over budget, defer
186
- this._deferredTasks.push({ fn: task, priority, label });
187
-
188
- // Sort by priority (higher first)
189
- this._deferredTasks.sort((a, b) => b.priority - a.priority);
190
- }
191
- }
192
-
193
- /**
194
- * Get current FPS
195
- * @returns {number} Average FPS over recent frames
196
- */
197
- getFps() {
198
- return Math.round(this._currentFps);
199
- }
200
-
201
- /**
202
- * Get performance stats
203
- * @returns {object} Performance statistics
204
- */
205
- getStats() {
206
- return {
207
- fps: this.getFps(),
208
- frameCount: this._frameCount,
209
- deferredTaskCount: this._deferredTasks.length,
210
- running: this._running
211
- };
212
- }
213
-
214
- /**
215
- * Check if loop is running
216
- * @returns {boolean} True if running
217
- */
218
- isRunning() {
219
- return this._running;
220
- }
221
-
222
- /**
223
- * Get frame count
224
- * @returns {number} Total frames rendered
225
- */
226
- getFrameCount() {
227
- return this._frameCount;
228
- }
229
-
230
- /**
231
- * Clear all deferred tasks
232
- */
233
- clearDeferredTasks() {
234
- this._deferredTasks.length = 0;
235
- logger.debug('Cleared all deferred tasks');
236
- }
237
- }
238
-
239
- /**
240
- * FrameBudgetMonitor - Monitors and alerts on frame budget violations
241
- */
242
- export class FrameBudgetMonitor {
243
- /**
244
- * Create a FrameBudgetMonitor
245
- * @param {number} [targetFps=60] - Target FPS
246
- * @param {Function} [onViolation] - Callback when budget is violated
247
- */
248
- constructor(targetFps = 60, onViolation = null) {
249
- this._targetFps = targetFps;
250
- this._frameBudget = 1000 / targetFps;
251
- this._onViolation = onViolation;
252
- this._violations = 0;
253
- this._frameStart = 0;
254
- }
255
-
256
- /**
257
- * Mark start of frame
258
- */
259
- startFrame() {
260
- this._frameStart = performance.now();
261
- }
262
-
263
- /**
264
- * Check if frame is within budget
265
- * @param {string} [location] - Location identifier for debugging
266
- * @returns {boolean} True if within budget
267
- */
268
- checkBudget(location = '') {
269
- const elapsed = performance.now() - this._frameStart;
270
- const withinBudget = elapsed < this._frameBudget;
271
-
272
- if (!withinBudget) {
273
- this._violations++;
274
-
275
- if (this._onViolation) {
276
- this._onViolation({
277
- location,
278
- elapsed,
279
- budget: this._frameBudget,
280
- overrun: elapsed - this._frameBudget
281
- });
282
- }
283
-
284
- logger.warn(`Frame budget violation at ${location}: ${elapsed.toFixed(2)}ms / ${this._frameBudget.toFixed(2)}ms`);
285
- }
286
-
287
- return withinBudget;
288
- }
289
-
290
- /**
291
- * Get violation count
292
- * @returns {number} Total violations
293
- */
294
- getViolationCount() {
295
- return this._violations;
296
- }
297
-
298
- /**
299
- * Reset violation count
300
- */
301
- resetViolations() {
302
- this._violations = 0;
303
- }
304
- }
305
-
306
- export default RenderLoop;
package/src/utils/Util.js DELETED
@@ -1,416 +0,0 @@
1
- /**
2
- * Core utility functions for Gaussian Splat rendering
3
- *
4
- * Derived from @mkkellogg/gaussian-splats-3d (MIT License)
5
- * https://github.com/mkkellogg/GaussianSplats3D
6
- *
7
- * Import paths adjusted for gsplat-flame-avatar package structure.
8
- */
9
-
10
- import { DataUtils } from 'three';
11
- import { NetworkError } from '../errors/index.js';
12
- import { getLogger } from './Logger.js';
13
-
14
- const logger = getLogger('Util');
15
-
16
- /**
17
- * Custom error for aborted operations
18
- * @deprecated Use NetworkError instead for consistency
19
- */
20
- export class AbortedPromiseError extends Error {
21
- constructor(msg) {
22
- super(msg);
23
- this.name = 'AbortedPromiseError';
24
- this.code = 'ABORTED';
25
- }
26
- }
27
-
28
- /**
29
- * Fetch with progress tracking using standard AbortController
30
- *
31
- * @param {string} path - URL to fetch
32
- * @param {Function} [onProgress] - Progress callback (percent, percentLabel, chunk, fileSize)
33
- * @param {boolean} [saveChunks=true] - Whether to save and return downloaded chunks
34
- * @param {object} [headers] - Optional HTTP headers
35
- * @returns {Promise<ArrayBuffer>} Promise that resolves with downloaded data
36
- * @throws {NetworkError} If fetch fails or is aborted
37
- */
38
- export const fetchWithProgress = function(path, onProgress, saveChunks = true, headers) {
39
-
40
- const abortController = new AbortController();
41
- const signal = abortController.signal;
42
- let aborted = false;
43
-
44
- let onProgressCalledAtComplete = false;
45
- const localOnProgress = (percent, percentLabel, chunk, fileSize) => {
46
- if (onProgress && !onProgressCalledAtComplete) {
47
- try {
48
- onProgress(percent, percentLabel, chunk, fileSize);
49
- if (percent === 100) {
50
- onProgressCalledAtComplete = true;
51
- }
52
- } catch (error) {
53
- // Don't let progress callback errors break the download
54
- logger.error('Error in progress callback:', error);
55
- }
56
- }
57
- };
58
-
59
- const promise = new Promise((resolve, reject) => {
60
- const fetchOptions = { signal };
61
- if (headers) fetchOptions.headers = headers;
62
-
63
- fetch(path, fetchOptions)
64
- .then(async (data) => {
65
- // Handle HTTP error responses
66
- if (!data.ok) {
67
- let errorText = '';
68
- try {
69
- errorText = await data.text();
70
- } catch {
71
- // Ignore if we can't read error text
72
- }
73
- reject(new NetworkError(
74
- `Fetch failed: ${data.statusText}${errorText ? ' - ' + errorText : ''}`,
75
- data.status
76
- ));
77
- return;
78
- }
79
-
80
- const reader = data.body?.getReader();
81
- if (!reader) {
82
- reject(new NetworkError('Response body is not readable', 0));
83
- return;
84
- }
85
-
86
- let bytesDownloaded = 0;
87
- const _fileSize = data.headers.get('Content-Length');
88
- const fileSize = _fileSize ? parseInt(_fileSize, 10) : undefined;
89
-
90
- const chunks = [];
91
-
92
- while (!aborted) {
93
- try {
94
- const { value: chunk, done } = await reader.read();
95
- if (done) {
96
- localOnProgress(100, '100%', chunk, fileSize);
97
- if (saveChunks) {
98
- const buffer = new Blob(chunks).arrayBuffer();
99
- resolve(buffer);
100
- } else {
101
- resolve();
102
- }
103
- break;
104
- }
105
- bytesDownloaded += chunk.length;
106
- let percent;
107
- let percentLabel;
108
- if (fileSize !== undefined) {
109
- percent = (bytesDownloaded / fileSize) * 100;
110
- percentLabel = `${percent.toFixed(2)}%`;
111
- }
112
- if (saveChunks) {
113
- chunks.push(chunk);
114
- }
115
- localOnProgress(percent, percentLabel, chunk, fileSize);
116
- } catch (error) {
117
- reject(new NetworkError(
118
- `Error reading response stream: ${error.message}`,
119
- 0,
120
- error
121
- ));
122
- return;
123
- }
124
- }
125
- })
126
- .catch((error) => {
127
- // Don't wrap if already a NetworkError
128
- if (error instanceof NetworkError) {
129
- reject(error);
130
- } else if (error.name === 'AbortError') {
131
- reject(new NetworkError('Fetch aborted by user', 0, error));
132
- } else {
133
- reject(new NetworkError(
134
- `Fetch failed: ${error.message || 'Unknown error'}`,
135
- 0,
136
- error
137
- ));
138
- }
139
- });
140
- });
141
-
142
- // Attach abort functionality to the promise
143
- promise.abort = (reason) => {
144
- aborted = true;
145
- abortController.abort(reason);
146
- };
147
- promise.abortController = abortController;
148
-
149
- return promise;
150
- };
151
-
152
- // Clamp value between min and max
153
- export const clamp = function(val, min, max) {
154
- return Math.max(Math.min(val, max), min);
155
- };
156
-
157
- // Get current time in seconds
158
- export const getCurrentTime = function() {
159
- return performance.now() / 1000;
160
- };
161
-
162
- // Dispose all meshes in a scene graph
163
- export const disposeAllMeshes = (object3D) => {
164
- if (object3D.geometry) {
165
- object3D.geometry.dispose();
166
- object3D.geometry = null;
167
- }
168
- if (object3D.material) {
169
- object3D.material.dispose();
170
- object3D.material = null;
171
- }
172
- if (object3D.children) {
173
- for (let child of object3D.children) {
174
- disposeAllMeshes(child);
175
- }
176
- }
177
- };
178
-
179
- // Delayed execution helper
180
- export const delayedExecute = (func, fast) => {
181
- return new Promise((resolve) => {
182
- window.setTimeout(() => {
183
- resolve(func());
184
- }, fast ? 1 : 50);
185
- });
186
- };
187
-
188
- // Get spherical harmonics component count for degree
189
- export const getSphericalHarmonicsComponentCountForDegree = (sphericalHarmonicsDegree = 0) => {
190
- switch (sphericalHarmonicsDegree) {
191
- case 1:
192
- return 9;
193
- case 2:
194
- return 24;
195
- }
196
- return 0;
197
- };
198
-
199
- // Create native promise with extracted components
200
- export const nativePromiseWithExtractedComponents = () => {
201
- let resolver;
202
- let rejecter;
203
- const promise = new Promise((resolve, reject) => {
204
- resolver = resolve;
205
- rejecter = reject;
206
- });
207
- return {
208
- 'promise': promise,
209
- 'resolve': resolver,
210
- 'reject': rejecter
211
- };
212
- };
213
-
214
- /**
215
- * Create a promise with extracted resolve/reject functions and optional abort capability
216
- * Uses standard Promise with attached abort method
217
- */
218
- export const abortablePromiseWithExtractedComponents = (abortHandler) => {
219
- let resolver;
220
- let rejecter;
221
- const promise = new Promise((resolve, reject) => {
222
- resolver = resolve;
223
- rejecter = reject;
224
- });
225
-
226
- // Attach abort method to promise
227
- promise.abort = abortHandler || (() => {});
228
-
229
- return {
230
- 'promise': promise,
231
- 'resolve': resolver,
232
- 'reject': rejecter
233
- };
234
- };
235
-
236
- // Semver class for version handling
237
- export class Semver {
238
- constructor(major, minor, patch) {
239
- this.major = major;
240
- this.minor = minor;
241
- this.patch = patch;
242
- }
243
-
244
- toString() {
245
- return `${this.major}_${this.minor}_${this.patch}`;
246
- }
247
- }
248
-
249
- // iOS detection
250
- export function isIOS() {
251
- const ua = navigator.userAgent;
252
- return ua.indexOf('iPhone') > 0 || ua.indexOf('iPad') > 0;
253
- }
254
-
255
- export function getIOSSemever() {
256
- if (isIOS()) {
257
- const extract = navigator.userAgent.match(/OS (\d+)_(\d+)_?(\d+)?/);
258
- return new Semver(
259
- parseInt(extract[1] || 0, 10),
260
- parseInt(extract[2] || 0, 10),
261
- parseInt(extract[3] || 0, 10)
262
- );
263
- }
264
- return null;
265
- }
266
-
267
- // Half float conversion utilities
268
- export const toHalfFloat = DataUtils.toHalfFloat.bind(DataUtils);
269
- export const fromHalfFloat = DataUtils.fromHalfFloat.bind(DataUtils);
270
-
271
- // Default spherical harmonics compression range (imported from enums)
272
- import { DefaultSphericalHarmonics8BitCompressionRange } from '../enums/EngineConstants.js';
273
- export { DefaultSphericalHarmonics8BitCompressionRange };
274
- export const DefaultSphericalHarmonics8BitCompressionHalfRange = DefaultSphericalHarmonics8BitCompressionRange / 2.0;
275
-
276
- // Uncompress float based on compression level
277
- export const toUncompressedFloat = (f, compressionLevel, isSH = false, range8BitMin, range8BitMax) => {
278
- if (compressionLevel === 0) {
279
- return f;
280
- } else if (compressionLevel === 1 || (compressionLevel === 2 && !isSH)) {
281
- return DataUtils.fromHalfFloat(f);
282
- } else if (compressionLevel === 2) {
283
- return fromUint8(f, range8BitMin, range8BitMax);
284
- }
285
- };
286
-
287
- // Convert to uint8
288
- export const toUint8 = (v, rangeMin, rangeMax) => {
289
- v = clamp(v, rangeMin, rangeMax);
290
- const range = (rangeMax - rangeMin);
291
- return clamp(Math.floor((v - rangeMin) / range * 255), 0, 255);
292
- };
293
-
294
- // Convert from uint8
295
- export const fromUint8 = (v, rangeMin, rangeMax) => {
296
- const range = (rangeMax - rangeMin);
297
- return (v / 255 * range + rangeMin);
298
- };
299
-
300
- // Half float to uint8
301
- export const fromHalfFloatToUint8 = (v, rangeMin, rangeMax) => {
302
- return toUint8(fromHalfFloat(v), rangeMin, rangeMax);
303
- };
304
-
305
- // Uint8 to half float
306
- export const fromUint8ToHalfFloat = (v, rangeMin, rangeMax) => {
307
- return toHalfFloat(fromUint8(v, rangeMin, rangeMax));
308
- };
309
-
310
- // Read float from DataView based on compression level
311
- export const dataViewFloatForCompressionLevel = (dataView, floatIndex, compressionLevel, isSH = false) => {
312
- if (compressionLevel === 0) {
313
- return dataView.getFloat32(floatIndex * 4, true);
314
- } else if (compressionLevel === 1 || (compressionLevel === 2 && !isSH)) {
315
- return dataView.getUint16(floatIndex * 2, true);
316
- } else {
317
- return dataView.getUint8(floatIndex, true);
318
- }
319
- };
320
-
321
- // Convert between compression levels
322
- export const convertBetweenCompressionLevels = function() {
323
- const noop = (v) => v;
324
-
325
- return function(val, fromLevel, toLevel, isSH = false) {
326
- if (fromLevel === toLevel) return val;
327
- let outputConversionFunc = noop;
328
-
329
- if (fromLevel === 2 && isSH) {
330
- if (toLevel === 1) outputConversionFunc = fromUint8ToHalfFloat;
331
- else if (toLevel === 0) {
332
- outputConversionFunc = fromUint8;
333
- }
334
- } else if (fromLevel === 2 || fromLevel === 1) {
335
- if (toLevel === 0) outputConversionFunc = fromHalfFloat;
336
- else if (toLevel === 2) {
337
- if (!isSH) outputConversionFunc = noop;
338
- else outputConversionFunc = fromHalfFloatToUint8;
339
- }
340
- } else if (fromLevel === 0) {
341
- if (toLevel === 1) outputConversionFunc = toHalfFloat;
342
- else if (toLevel === 2) {
343
- if (!isSH) outputConversionFunc = toHalfFloat;
344
- else outputConversionFunc = toUint8;
345
- }
346
- }
347
-
348
- return outputConversionFunc(val);
349
- };
350
- }();
351
-
352
- // Copy between buffers
353
- export const copyBetweenBuffers = (srcBuffer, srcOffset, destBuffer, destOffset, byteCount = 0) => {
354
- const src = new Uint8Array(srcBuffer, srcOffset);
355
- const dest = new Uint8Array(destBuffer, destOffset);
356
- for (let i = 0; i < byteCount; i++) {
357
- dest[i] = src[i];
358
- }
359
- };
360
-
361
- // Float to half float conversion
362
- export const floatToHalf = function() {
363
- const floatView = new Float32Array(1);
364
- const int32View = new Int32Array(floatView.buffer);
365
-
366
- return function(val) {
367
- floatView[0] = val;
368
- const x = int32View[0];
369
-
370
- let bits = (x >> 16) & 0x8000;
371
- let m = (x >> 12) & 0x07ff;
372
- const e = (x >> 23) & 0xff;
373
-
374
- if (e < 103) return bits;
375
-
376
- if (e > 142) {
377
- bits |= 0x7c00;
378
- bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
379
- return bits;
380
- }
381
-
382
- if (e < 113) {
383
- m |= 0x0800;
384
- bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
385
- return bits;
386
- }
387
-
388
- bits |= ((e - 112) << 10) | (m >> 1);
389
- bits += m & 1;
390
- return bits;
391
- };
392
- }();
393
-
394
- // Encode float as uint
395
- export const uintEncodedFloat = function() {
396
- const floatView = new Float32Array(1);
397
- const int32View = new Int32Array(floatView.buffer);
398
-
399
- return function(f) {
400
- floatView[0] = f;
401
- return int32View[0];
402
- };
403
- }();
404
-
405
- // RGBA to integer
406
- export const rgbaToInteger = function(r, g, b, a) {
407
- return r + (g << 8) + (b << 16) + (a << 24);
408
- };
409
-
410
- // RGBA array to integer
411
- export const rgbaArrayToInteger = function(arr, offset) {
412
- return arr[offset] + (arr[offset + 1] << 8) + (arr[offset + 2] << 16) + (arr[offset + 3] << 24);
413
- };
414
-
415
- // BASE_COMPONENT_COUNT for UncompressedSplatArray
416
- export const BASE_COMPONENT_COUNT = 14;