@manycore/aholo-splat-transform 1.2.7 → 1.2.9

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 (98) hide show
  1. package/CHANGELOG.md +120 -106
  2. package/COPYRIGHT.md +17 -0
  3. package/README.md +39 -39
  4. package/THIRD_PARTY_LICENSES.txt +1373 -0
  5. package/bin/cli.js +125 -118
  6. package/dist/SplatData.d.ts +67 -67
  7. package/dist/SplatData.js +167 -156
  8. package/dist/constant.d.ts +3 -3
  9. package/dist/constant.js +13 -13
  10. package/dist/file/IFile.d.ts +5 -5
  11. package/dist/file/IFile.js +1 -1
  12. package/dist/file/esz.d.ts +11 -0
  13. package/dist/file/esz.js +337 -0
  14. package/dist/file/index.d.ts +8 -7
  15. package/dist/file/index.js +7 -6
  16. package/dist/file/ksplat.d.ts +12 -12
  17. package/dist/file/ksplat.js +293 -232
  18. package/dist/file/lcc.d.ts +11 -11
  19. package/dist/file/lcc.js +161 -157
  20. package/dist/file/ply.d.ts +13 -13
  21. package/dist/file/ply.js +439 -388
  22. package/dist/file/sog.d.ts +80 -80
  23. package/dist/file/sog.js +525 -504
  24. package/dist/file/splat.d.ts +6 -6
  25. package/dist/file/splat.js +119 -99
  26. package/dist/file/spz.d.ts +11 -8
  27. package/dist/file/spz.js +597 -400
  28. package/dist/file/voxel.d.ts +43 -37
  29. package/dist/file/voxel.js +411 -280
  30. package/dist/index.d.ts +33 -33
  31. package/dist/index.js +54 -54
  32. package/dist/native/index.d.ts +54 -54
  33. package/dist/native/index.js +122 -128
  34. package/dist/native/utils.d.ts +1 -0
  35. package/dist/native/utils.js +54 -0
  36. package/dist/tasks/AutoChunkLodTask.d.ts +13 -13
  37. package/dist/tasks/AutoChunkLodTask.js +117 -117
  38. package/dist/tasks/AutoLodTask.d.ts +10 -10
  39. package/dist/tasks/AutoLodTask.js +20 -20
  40. package/dist/tasks/BaseTask.d.ts +15 -15
  41. package/dist/tasks/BaseTask.js +5 -5
  42. package/dist/tasks/FlexLodTask.d.ts +12 -12
  43. package/dist/tasks/FlexLodTask.js +54 -44
  44. package/dist/tasks/ModifyTask.d.ts +9 -9
  45. package/dist/tasks/ModifyTask.js +166 -156
  46. package/dist/tasks/ReadTask.d.ts +9 -9
  47. package/dist/tasks/ReadTask.js +29 -29
  48. package/dist/tasks/SkeletonLodTask.d.ts +10 -10
  49. package/dist/tasks/SkeletonLodTask.js +176 -156
  50. package/dist/tasks/VoxelTask.d.ts +35 -30
  51. package/dist/tasks/VoxelTask.js +40 -37
  52. package/dist/tasks/WriteTask.d.ts +12 -11
  53. package/dist/tasks/WriteTask.js +70 -70
  54. package/dist/utils/BufferReader.d.ts +12 -12
  55. package/dist/utils/BufferReader.js +45 -47
  56. package/dist/utils/Logger.d.ts +11 -11
  57. package/dist/utils/Logger.js +40 -38
  58. package/dist/utils/StreamChunkDecoder.d.ts +16 -16
  59. package/dist/utils/StreamChunkDecoder.js +31 -36
  60. package/dist/utils/index.d.ts +27 -27
  61. package/dist/utils/index.js +101 -101
  62. package/dist/utils/k-means.d.ts +4 -4
  63. package/dist/utils/k-means.js +340 -350
  64. package/dist/utils/math.d.ts +46 -46
  65. package/dist/utils/math.js +350 -351
  66. package/dist/utils/quantize-1d.d.ts +4 -4
  67. package/dist/utils/quantize-1d.js +164 -164
  68. package/dist/utils/sh-rotate.d.ts +2 -2
  69. package/dist/utils/sh-rotate.js +236 -175
  70. package/dist/utils/splat.d.ts +21 -20
  71. package/dist/utils/splat.js +397 -378
  72. package/dist/utils/voxel/binary.d.ts +8 -0
  73. package/dist/utils/voxel/binary.js +176 -0
  74. package/dist/utils/voxel/common.d.ts +178 -162
  75. package/dist/utils/voxel/common.js +1752 -1700
  76. package/dist/utils/voxel/coplanar-merge.d.ts +63 -63
  77. package/dist/utils/voxel/coplanar-merge.js +818 -819
  78. package/dist/utils/voxel/filter-cluster.d.ts +20 -0
  79. package/dist/utils/voxel/filter-cluster.js +628 -0
  80. package/dist/utils/voxel/gpu-dilation.d.ts +2 -2
  81. package/dist/utils/voxel/gpu-dilation.js +677 -665
  82. package/dist/utils/voxel/marching-cubes.d.ts +42 -42
  83. package/dist/utils/voxel/marching-cubes.js +1645 -1657
  84. package/dist/utils/voxel/mesh.d.ts +3 -3
  85. package/dist/utils/voxel/mesh.js +130 -130
  86. package/dist/utils/voxel/nav.d.ts +29 -29
  87. package/dist/utils/voxel/nav.js +1068 -1043
  88. package/dist/utils/voxel/postprocess.d.ts +23 -23
  89. package/dist/utils/voxel/postprocess.js +408 -375
  90. package/dist/utils/voxel/voxel-faces.d.ts +18 -18
  91. package/dist/utils/voxel/voxel-faces.js +662 -663
  92. package/dist/utils/voxel/voxelize.d.ts +34 -33
  93. package/dist/utils/voxel/voxelize.js +1208 -1193
  94. package/dist/utils/webgpu.d.ts +8 -8
  95. package/dist/utils/webgpu.js +122 -122
  96. package/package.json +37 -30
  97. package/dist/native/cpp/bin/linux/binding.node +0 -0
  98. package/dist/native/cpp/bin/windows/binding.node +0 -0
package/dist/index.d.ts CHANGED
@@ -1,33 +1,33 @@
1
- import { Config as AutoChunkLodConfig } from './tasks/AutoChunkLodTask.js';
2
- import { Config as AutoLodConfig } from './tasks/AutoLodTask.js';
3
- import { Config as FlexLodConfig } from './tasks/FlexLodTask.js';
4
- import { Config as SkeletonLodConfig } from './tasks/SkeletonLodTask.js';
5
- import { Config as ModifyConfig } from './tasks/ModifyTask.js';
6
- import { Config as ReadConfig } from './tasks/ReadTask.js';
7
- import { Config as WriteConfig } from './tasks/WriteTask.js';
8
- import { VoxelTaskConfig } from './tasks/VoxelTask.js';
9
- interface TaskConfigMap {
10
- Read: ReadConfig;
11
- Write: WriteConfig;
12
- Voxel: VoxelTaskConfig;
13
- Modify: ModifyConfig;
14
- SkeletonLod: SkeletonLodConfig;
15
- FlexLod: FlexLodConfig;
16
- AutoLod: AutoLodConfig;
17
- AutoChunkLod: AutoChunkLodConfig;
18
- }
19
- type PipelineTask = {
20
- [K in keyof TaskConfigMap]: {
21
- id: string;
22
- type: K;
23
- config: TaskConfigMap[K];
24
- release?: string[];
25
- };
26
- }[keyof TaskConfigMap];
27
- interface PipelineConfig {
28
- version: number;
29
- gpu?: number;
30
- tasks: PipelineTask[];
31
- }
32
- export declare function runner(config: PipelineConfig): Promise<void>;
33
- export {};
1
+ import { type Config as AutoChunkLodConfig } from './tasks/AutoChunkLodTask.js';
2
+ import { type Config as AutoLodConfig } from './tasks/AutoLodTask.js';
3
+ import { type Config as FlexLodConfig } from './tasks/FlexLodTask.js';
4
+ import { type Config as SkeletonLodConfig } from './tasks/SkeletonLodTask.js';
5
+ import { type Config as ModifyConfig } from './tasks/ModifyTask.js';
6
+ import { type Config as ReadConfig } from './tasks/ReadTask.js';
7
+ import { type Config as WriteConfig } from './tasks/WriteTask.js';
8
+ import { type VoxelTaskConfig } from './tasks/VoxelTask.js';
9
+ interface TaskConfigMap {
10
+ Read: ReadConfig;
11
+ Write: WriteConfig;
12
+ Voxel: VoxelTaskConfig;
13
+ Modify: ModifyConfig;
14
+ SkeletonLod: SkeletonLodConfig;
15
+ FlexLod: FlexLodConfig;
16
+ AutoLod: AutoLodConfig;
17
+ AutoChunkLod: AutoChunkLodConfig;
18
+ }
19
+ type PipelineTask = {
20
+ [K in keyof TaskConfigMap]: {
21
+ id: string;
22
+ type: K;
23
+ config: TaskConfigMap[K];
24
+ release?: string[];
25
+ };
26
+ }[keyof TaskConfigMap];
27
+ interface PipelineConfig {
28
+ version: number;
29
+ gpu?: number;
30
+ tasks: PipelineTask[];
31
+ }
32
+ export declare function runner(config: PipelineConfig): Promise<void>;
33
+ export {};
package/dist/index.js CHANGED
@@ -1,54 +1,54 @@
1
- import { AutoChunkLodTask } from './tasks/AutoChunkLodTask.js';
2
- import { AutoLodTask } from './tasks/AutoLodTask.js';
3
- import { FlexLodTask } from './tasks/FlexLodTask.js';
4
- import { SkeletonLodTask } from './tasks/SkeletonLodTask.js';
5
- import { ModifyTask } from './tasks/ModifyTask.js';
6
- import { ReadTask } from './tasks/ReadTask.js';
7
- import { WriteTask } from './tasks/WriteTask.js';
8
- import { VoxelTask } from './tasks/VoxelTask.js';
9
- import { enumerateAdapters, logger, releaseSharedDevice, initGPUAdapter } from './utils/index.js';
10
- const TaskMap = {
11
- Read: new ReadTask(),
12
- Write: new WriteTask(),
13
- Voxel: new VoxelTask(),
14
- Modify: new ModifyTask(),
15
- SkeletonLod: new SkeletonLodTask(),
16
- FlexLod: new FlexLodTask(),
17
- AutoLod: new AutoLodTask(),
18
- AutoChunkLod: new AutoChunkLodTask(),
19
- };
20
- function anyTaskRequireGPU(tasks) {
21
- for (const t of tasks) {
22
- if (TaskMap[t.type].requiresGPU(t.config)) {
23
- return true;
24
- }
25
- }
26
- return false;
27
- }
28
- export async function runner(config) {
29
- console.time('Total elapsed time');
30
- const ctx = {
31
- logger,
32
- resources: new Map(),
33
- };
34
- if (anyTaskRequireGPU(config.tasks)) {
35
- logger.prefix = `[Task:GPU]`;
36
- logger.info('Any task requires GPU detected, initialize GPU adapter.');
37
- const adapter = (await enumerateAdapters())[config.gpu ?? 0];
38
- initGPUAdapter([`adapter=${adapter.name}`]);
39
- }
40
- for (const taskDef of config.tasks) {
41
- const { id, type, config: taskConfig, release = [] } = taskDef;
42
- const task = TaskMap[type];
43
- if (!task) {
44
- throw new Error(`Task not found: ${type} (id: ${id})`);
45
- }
46
- logger.prefix = `[Task:${type}#${id}]`;
47
- logger.time('elapsed time');
48
- await task.exec(taskConfig, ctx);
49
- release.forEach(v => ctx.resources.delete(v));
50
- logger.timeEnd('elapsed time');
51
- }
52
- releaseSharedDevice();
53
- console.timeEnd('Total elapsed time');
54
- }
1
+ import { AutoChunkLodTask } from './tasks/AutoChunkLodTask.js';
2
+ import { AutoLodTask } from './tasks/AutoLodTask.js';
3
+ import { FlexLodTask } from './tasks/FlexLodTask.js';
4
+ import { SkeletonLodTask } from './tasks/SkeletonLodTask.js';
5
+ import { ModifyTask } from './tasks/ModifyTask.js';
6
+ import { ReadTask } from './tasks/ReadTask.js';
7
+ import { WriteTask } from './tasks/WriteTask.js';
8
+ import { VoxelTask } from './tasks/VoxelTask.js';
9
+ import { enumerateAdapters, logger, releaseSharedDevice, initGPUAdapter } from './utils/index.js';
10
+ const TaskMap = {
11
+ Read: new ReadTask(),
12
+ Write: new WriteTask(),
13
+ Voxel: new VoxelTask(),
14
+ Modify: new ModifyTask(),
15
+ SkeletonLod: new SkeletonLodTask(),
16
+ FlexLod: new FlexLodTask(),
17
+ AutoLod: new AutoLodTask(),
18
+ AutoChunkLod: new AutoChunkLodTask(),
19
+ };
20
+ function anyTaskRequireGPU(tasks) {
21
+ for (const t of tasks) {
22
+ if (TaskMap[t.type].requiresGPU(t.config)) {
23
+ return true;
24
+ }
25
+ }
26
+ return false;
27
+ }
28
+ export async function runner(config) {
29
+ console.time('Total elapsed time');
30
+ const ctx = {
31
+ logger,
32
+ resources: new Map(),
33
+ };
34
+ if (anyTaskRequireGPU(config.tasks)) {
35
+ logger.prefix = `[Task:GPU]`;
36
+ logger.info('Any task requires GPU detected, initialize GPU adapter.');
37
+ const adapter = (await enumerateAdapters())[config.gpu ?? 0];
38
+ initGPUAdapter([`adapter=${adapter.name}`]);
39
+ }
40
+ for (const taskDef of config.tasks) {
41
+ const { id, type, config: taskConfig, release = [] } = taskDef;
42
+ const task = TaskMap[type];
43
+ if (!task) {
44
+ throw new Error(`Task not found: ${type} (id: ${id})`);
45
+ }
46
+ logger.prefix = `[Task:${type}#${id}]`;
47
+ logger.time('elapsed time');
48
+ await task.exec(taskConfig, ctx);
49
+ release.forEach(v => ctx.resources.delete(v));
50
+ logger.timeEnd('elapsed time');
51
+ }
52
+ releaseSharedDevice();
53
+ console.timeEnd('Total elapsed time');
54
+ }
@@ -1,54 +1,54 @@
1
- import { SplatData } from '../SplatData.js';
2
- import { Buffer } from 'node:buffer';
3
- export interface LevelParameter {
4
- precision: number;
5
- scaleBoost: number;
6
- }
7
- export interface BlockedSplats {
8
- box: {
9
- min: [number, number, number];
10
- max: [number, number, number];
11
- };
12
- /**
13
- * current block referenced splats, level ordered.
14
- */
15
- refs: number[];
16
- }
17
- export interface BlockedResult {
18
- splats: SplatData[];
19
- blocks: BlockedSplats[];
20
- }
21
- export declare function generateLod(splat: SplatData, levelParameters: LevelParameter[], blockPrecision: number, minSize: number, maxStep: number): BlockedResult;
22
- export declare class WebPLosslessProfile {
23
- readonly lossless = true;
24
- }
25
- export declare class WebPQualityProfile {
26
- readonly quality: number;
27
- readonly lossless = false;
28
- constructor(quality: number);
29
- }
30
- export declare function encodeWebP(data: Uint8Array | Buffer, width: number, height: number, profile: WebPLosslessProfile | WebPQualityProfile): Buffer<ArrayBufferLike>;
31
- export declare function decodeWebP(data: Uint8Array | Buffer): {
32
- data: Buffer;
33
- width: number;
34
- height: number;
35
- };
36
- export declare function encodeAVIF(data: Uint8Array | Buffer, width: number, height: number, quality: number): Buffer<ArrayBufferLike>;
37
- export interface AVIFEncodeInput {
38
- data: Uint8Array | Buffer;
39
- width: number;
40
- height: number;
41
- quality: number;
42
- }
43
- export declare function encodeAVIFBatched(inputs: AVIFEncodeInput[]): Buffer<ArrayBufferLike>[];
44
- export declare function decodeAVIF(data: Uint8Array | Buffer): {
45
- data: Buffer;
46
- width: number;
47
- height: number;
48
- };
49
- export declare function decodeAVIFBatched(inputs: Array<Uint8Array | Buffer>): {
50
- data: Buffer;
51
- width: number;
52
- height: number;
53
- }[];
54
- export declare function clusterAverage(dataTable: Float32Array[], clusters: Uint32Array[], output: Float32Array[]): void;
1
+ import { SplatData } from '../SplatData.js';
2
+ import { Buffer } from 'node:buffer';
3
+ export interface LevelParameter {
4
+ precision: number;
5
+ scaleBoost: number;
6
+ }
7
+ export interface BlockedSplats {
8
+ box: {
9
+ min: [number, number, number];
10
+ max: [number, number, number];
11
+ };
12
+ /**
13
+ * current block referenced splats, level ordered.
14
+ */
15
+ refs: number[];
16
+ }
17
+ export interface BlockedResult {
18
+ splats: SplatData[];
19
+ blocks: BlockedSplats[];
20
+ }
21
+ export declare function generateLod(splat: SplatData, levelParameters: LevelParameter[], blockPrecision: number, minSize: number, maxStep: number): BlockedResult;
22
+ export declare class WebPLosslessProfile {
23
+ readonly lossless = true;
24
+ }
25
+ export declare class WebPQualityProfile {
26
+ readonly quality: number;
27
+ readonly lossless = false;
28
+ constructor(quality: number);
29
+ }
30
+ export declare function encodeWebP(data: Uint8Array | Buffer, width: number, height: number, profile: WebPLosslessProfile | WebPQualityProfile): Buffer<ArrayBufferLike>;
31
+ export declare function decodeWebP(data: Uint8Array | Buffer): {
32
+ data: Buffer;
33
+ width: number;
34
+ height: number;
35
+ };
36
+ export declare function encodeAVIF(data: Uint8Array | Buffer, width: number, height: number, quality: number): Buffer<ArrayBufferLike>;
37
+ export interface AVIFEncodeInput {
38
+ data: Uint8Array | Buffer;
39
+ width: number;
40
+ height: number;
41
+ quality: number;
42
+ }
43
+ export declare function encodeAVIFBatched(inputs: AVIFEncodeInput[]): Buffer<ArrayBufferLike>[];
44
+ export declare function decodeAVIF(data: Uint8Array | Buffer): {
45
+ data: Buffer;
46
+ width: number;
47
+ height: number;
48
+ };
49
+ export declare function decodeAVIFBatched(inputs: Array<Uint8Array | Buffer>): {
50
+ data: Buffer;
51
+ width: number;
52
+ height: number;
53
+ }[];
54
+ export declare function clusterAverage(dataTable: Float32Array[], clusters: Uint32Array[], output: Float32Array[]): void;
@@ -1,128 +1,122 @@
1
- import * as child_process from 'node:child_process';
2
- import * as path from 'node:path';
3
- import * as os from 'node:os';
4
- import { createRequire } from 'node:module';
5
- import { SplatData } from '../SplatData.js';
6
- import { Buffer } from 'node:buffer';
7
- const getModule = (function () {
8
- let m = undefined;
9
- const require = createRequire(import.meta.url);
10
- const platform = os.platform();
11
- const binaryPath = `./cpp/bin/${platform === 'win32' ? 'windows' : platform}/binding.node`;
12
- return function () {
13
- if (!m) {
14
- try {
15
- m = require(binaryPath);
16
- }
17
- catch {
18
- console.warn(`cannot find a valid binary at: ${binaryPath}, try rebuild`);
19
- child_process.spawnSync('node', [
20
- require.resolve('cmake-js/bin/cmake-js'),
21
- 'build',
22
- '--',
23
- '--preset',
24
- 'default'
25
- ], {
26
- cwd: path.join(import.meta.dirname, 'cpp'),
27
- stdio: 'inherit'
28
- });
29
- m = require(binaryPath);
30
- }
31
- }
32
- return m;
33
- };
34
- })();
35
- export function generateLod(splat, levelParameters, blockPrecision, minSize, maxStep) {
36
- if (splat.counts === 0) {
37
- return {
38
- splats: [splat],
39
- blocks: [{
40
- box: { min: [0, 0, 0], max: [0, 0, 0] },
41
- refs: new Array(levelParameters.length).fill(0),
42
- }],
43
- };
44
- }
45
- const levels = levelParameters.length;
46
- const inputBuffers = splat.table.map(b => Buffer.from(b.buffer, b.byteOffset, b.byteLength));
47
- const buffer = Buffer.alloc(levels * 8);
48
- {
49
- const parameters = new Float32Array(buffer.buffer, buffer.byteOffset, levels * 2);
50
- for (let i = 0; i < levelParameters.length; i++) {
51
- const { precision, scaleBoost } = levelParameters[i];
52
- parameters[i * 2] = precision;
53
- parameters[i * 2 + 1] = scaleBoost;
54
- }
55
- }
56
- const { blockBoxes, blockRefs, gaussianCount, data, } = getModule().generate_lod(inputBuffers, splat.shCounts, buffer, blockPrecision, minSize, maxStep);
57
- const blockView = new Float32Array(blockBoxes.buffer, blockBoxes.byteOffset, blockBoxes.byteLength / 4);
58
- const blockRefsView = new Uint32Array(blockRefs.buffer, blockRefs.byteOffset, blockRefs.byteLength / 4);
59
- const blockCount = blockView.length / 6;
60
- const gaussianCountView = new Uint32Array(gaussianCount.buffer, gaussianCount.byteOffset, gaussianCount.byteLength / 4);
61
- const blocks = [];
62
- const splats = [];
63
- // read splats
64
- {
65
- let gaussianOffset = 0;
66
- for (const count of gaussianCountView) {
67
- const splatData = new SplatData(1, splat.shDegree);
68
- splatData.shDegree = splat.shDegree;
69
- splatData.shCounts = splat.shCounts;
70
- splatData.counts = count;
71
- splatData.table = data.map(buffer => new Float32Array(buffer.buffer, buffer.byteOffset + gaussianOffset * 4, count));
72
- splats.push(splatData);
73
- gaussianOffset += count;
74
- }
75
- }
76
- for (let i = 0; i < blockCount; i++) {
77
- const block = {
78
- box: {
79
- min: [blockView[i * 6], blockView[i * 6 + 1], blockView[i * 6 + 2]],
80
- max: [blockView[i * 6 + 3], blockView[i * 6 + 4], blockView[i * 6 + 5]]
81
- },
82
- refs: Array.from(blockRefsView.subarray(i * levels, i * levels + levels)),
83
- };
84
- blocks.push(block);
85
- }
86
- return { splats, blocks };
87
- }
88
- export class WebPLosslessProfile {
89
- lossless = true;
90
- }
91
- export class WebPQualityProfile {
92
- quality;
93
- lossless = false;
94
- constructor(quality) {
95
- this.quality = quality;
96
- }
97
- ;
98
- }
99
- export function encodeWebP(data, width, height, profile) {
100
- const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
101
- if (profile.lossless) {
102
- return getModule().webp_encode_rgba_lossless(buffer, width, height);
103
- }
104
- else {
105
- return getModule().webp_encode_rgba(buffer, width, height, profile.quality);
106
- }
107
- }
108
- export function decodeWebP(data) {
109
- const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
110
- return getModule().webp_decode_rgba(buffer);
111
- }
112
- export function encodeAVIF(data, width, height, quality) {
113
- const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
114
- return getModule().avif_encode_rgba(buffer, width, height, quality);
115
- }
116
- export function encodeAVIFBatched(inputs) {
117
- return getModule().avif_encode_rgba_batched(inputs.map(i => ({ ...i, data: i.data instanceof Buffer ? i.data : Buffer.from(i.data.buffer, i.data.byteOffset, i.data.byteLength) })));
118
- }
119
- export function decodeAVIF(data) {
120
- const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
121
- return getModule().avif_decode_rgba(buffer);
122
- }
123
- export function decodeAVIFBatched(inputs) {
124
- return getModule().avif_decode_rgba_batched(inputs.map(i => i instanceof Buffer ? i : Buffer.from(i.buffer, i.byteOffset, i.byteLength)));
125
- }
126
- export function clusterAverage(dataTable, clusters, output) {
127
- return getModule().cluster_average(dataTable.map(t => Buffer.from(t.buffer, t.byteOffset, t.byteLength)), clusters.map(t => Buffer.from(t.buffer, t.byteOffset, t.byteLength)), output.map(t => Buffer.from(t.buffer, t.byteOffset, t.byteLength)));
128
- }
1
+ import { createRequire } from 'node:module';
2
+ import { SplatData } from '../SplatData.js';
3
+ import { Buffer } from 'node:buffer';
4
+ import { isMusl } from './utils.js';
5
+ import p from '../../package.json' with { type: 'json' };
6
+ const getModule = (function () {
7
+ let m = undefined;
8
+ const require = createRequire(import.meta.url);
9
+ let runtime = undefined;
10
+ if (process.platform === 'win32') {
11
+ runtime = 'msvc';
12
+ }
13
+ else if (process.platform === 'linux') {
14
+ runtime = isMusl() ? 'musl' : 'gnu';
15
+ }
16
+ const binaryPackage = `${p.name}-${process.platform}-${process.arch}${runtime ? `-${runtime}` : ''}`;
17
+ return function () {
18
+ if (!m) {
19
+ m = require(binaryPackage);
20
+ }
21
+ return m;
22
+ };
23
+ })();
24
+ export function generateLod(splat, levelParameters, blockPrecision, minSize, maxStep) {
25
+ if (splat.counts === 0) {
26
+ return {
27
+ splats: [splat],
28
+ blocks: [
29
+ {
30
+ box: { min: [0, 0, 0], max: [0, 0, 0] },
31
+ refs: new Array(levelParameters.length).fill(0),
32
+ },
33
+ ],
34
+ };
35
+ }
36
+ const levels = levelParameters.length;
37
+ const inputBuffers = splat.table.map(b => Buffer.from(b.buffer, b.byteOffset, b.byteLength));
38
+ const buffer = Buffer.alloc(levels * 8);
39
+ {
40
+ const parameters = new Float32Array(buffer.buffer, buffer.byteOffset, levels * 2);
41
+ for (let i = 0; i < levelParameters.length; i++) {
42
+ const { precision, scaleBoost } = levelParameters[i];
43
+ parameters[i * 2] = precision;
44
+ parameters[i * 2 + 1] = scaleBoost;
45
+ }
46
+ }
47
+ const { blockBoxes, blockRefs, gaussianCount, data } = getModule().generate_lod(inputBuffers, splat.shCounts, buffer, blockPrecision, minSize, maxStep);
48
+ const blockView = new Float32Array(blockBoxes.buffer, blockBoxes.byteOffset, blockBoxes.byteLength / 4);
49
+ const blockRefsView = new Uint32Array(blockRefs.buffer, blockRefs.byteOffset, blockRefs.byteLength / 4);
50
+ const blockCount = blockView.length / 6;
51
+ const gaussianCountView = new Uint32Array(gaussianCount.buffer, gaussianCount.byteOffset, gaussianCount.byteLength / 4);
52
+ const blocks = [];
53
+ const splats = [];
54
+ // read splats
55
+ {
56
+ let gaussianOffset = 0;
57
+ for (const count of gaussianCountView) {
58
+ const splatData = new SplatData(1, splat.shDegree);
59
+ splatData.shDegree = splat.shDegree;
60
+ splatData.shCounts = splat.shCounts;
61
+ splatData.counts = count;
62
+ splatData.table = data.map(buffer => new Float32Array(buffer.buffer, buffer.byteOffset + gaussianOffset * 4, count));
63
+ splats.push(splatData);
64
+ gaussianOffset += count;
65
+ }
66
+ }
67
+ for (let i = 0; i < blockCount; i++) {
68
+ const block = {
69
+ box: {
70
+ min: [blockView[i * 6], blockView[i * 6 + 1], blockView[i * 6 + 2]],
71
+ max: [blockView[i * 6 + 3], blockView[i * 6 + 4], blockView[i * 6 + 5]],
72
+ },
73
+ refs: Array.from(blockRefsView.subarray(i * levels, i * levels + levels)),
74
+ };
75
+ blocks.push(block);
76
+ }
77
+ return { splats, blocks };
78
+ }
79
+ export class WebPLosslessProfile {
80
+ constructor() {
81
+ this.lossless = true;
82
+ }
83
+ }
84
+ export class WebPQualityProfile {
85
+ constructor(quality) {
86
+ this.quality = quality;
87
+ this.lossless = false;
88
+ }
89
+ }
90
+ export function encodeWebP(data, width, height, profile) {
91
+ const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
92
+ if (profile.lossless) {
93
+ return getModule().webp_encode_rgba_lossless(buffer, width, height);
94
+ }
95
+ else {
96
+ return getModule().webp_encode_rgba(buffer, width, height, profile.quality);
97
+ }
98
+ }
99
+ export function decodeWebP(data) {
100
+ const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
101
+ return getModule().webp_decode_rgba(buffer);
102
+ }
103
+ export function encodeAVIF(data, width, height, quality) {
104
+ const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
105
+ return getModule().avif_encode_rgba(buffer, width, height, quality);
106
+ }
107
+ export function encodeAVIFBatched(inputs) {
108
+ return getModule().avif_encode_rgba_batched(inputs.map(i => ({
109
+ ...i,
110
+ data: i.data instanceof Buffer ? i.data : Buffer.from(i.data.buffer, i.data.byteOffset, i.data.byteLength),
111
+ })));
112
+ }
113
+ export function decodeAVIF(data) {
114
+ const buffer = data instanceof Buffer ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
115
+ return getModule().avif_decode_rgba(buffer);
116
+ }
117
+ export function decodeAVIFBatched(inputs) {
118
+ return getModule().avif_decode_rgba_batched(inputs.map(i => (i instanceof Buffer ? i : Buffer.from(i.buffer, i.byteOffset, i.byteLength))));
119
+ }
120
+ export function clusterAverage(dataTable, clusters, output) {
121
+ return getModule().cluster_average(dataTable.map(t => Buffer.from(t.buffer, t.byteOffset, t.byteLength)), clusters.map(t => Buffer.from(t.buffer, t.byteOffset, t.byteLength)), output.map(t => Buffer.from(t.buffer, t.byteOffset, t.byteLength)));
122
+ }
@@ -0,0 +1 @@
1
+ export declare function isMusl(): boolean;
@@ -0,0 +1,54 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import child_process from 'node:child_process';
3
+ export function isMusl() {
4
+ let musl = false;
5
+ if (process.platform === 'linux') {
6
+ musl = isMuslFromFilesystem();
7
+ if (musl == null) {
8
+ musl = isMuslFromReport();
9
+ }
10
+ if (musl == null) {
11
+ musl = isMuslFromChildProcess();
12
+ }
13
+ }
14
+ return musl;
15
+ }
16
+ function isFileMusl(f) {
17
+ return f.includes('libc.musl-') || f.includes('ld-musl-');
18
+ }
19
+ function isMuslFromFilesystem() {
20
+ try {
21
+ return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl');
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ function isMuslFromReport() {
28
+ let report = null;
29
+ if (typeof process.report?.getReport === 'function') {
30
+ process.report.excludeNetwork = true;
31
+ report = process.report.getReport();
32
+ }
33
+ if (!report) {
34
+ return null;
35
+ }
36
+ if (report.header && report.header.glibcVersionRuntime) {
37
+ return false;
38
+ }
39
+ if (Array.isArray(report.sharedObjects)) {
40
+ if (report.sharedObjects.some(isFileMusl)) {
41
+ return true;
42
+ }
43
+ }
44
+ return false;
45
+ }
46
+ function isMuslFromChildProcess() {
47
+ try {
48
+ return child_process.execSync('ldd --version', { encoding: 'utf8' }).includes('musl');
49
+ }
50
+ catch {
51
+ // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false
52
+ return false;
53
+ }
54
+ }
@@ -1,13 +1,13 @@
1
- import { Context, BaseTask } from './BaseTask.js';
2
- import { LevelParameter } from '../native/index.js';
3
- export interface Config {
4
- input: string;
5
- output: string;
6
- type: string;
7
- maxChunkCounts?: number;
8
- levels?: LevelParameter[];
9
- }
10
- export declare class AutoChunkLodTask extends BaseTask<Config> {
11
- exec(config: Config, { logger, resources }: Context): Promise<void>;
12
- requiresGPU(config: Config): boolean;
13
- }
1
+ import { type Context, BaseTask } from './BaseTask.js';
2
+ import { type LevelParameter } from '../native/index.js';
3
+ export interface Config {
4
+ input: string;
5
+ output: string;
6
+ type: string;
7
+ maxChunkCounts?: number;
8
+ levels?: LevelParameter[];
9
+ }
10
+ export declare class AutoChunkLodTask extends BaseTask<Config> {
11
+ exec(config: Config, { logger, resources }: Context): Promise<void>;
12
+ requiresGPU(config: Config): boolean;
13
+ }