-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathspz.js
153 lines (129 loc) · 5.8 KB
/
spz.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// wasm generated from https://github.com/drumath2237/spz-loader/tree/main/packages/core/lib/spz-wasm
import spzwasm from "./lib/spz/spz.mjs";
const floatVectorToFloatArray = (wasmModule, vec, enhancementFunc = (n) => n) => {
const pointer = wasmModule.vf32_ptr(vec);
const size = vec.size();
const buffer = new Float32Array(wasmModule.HEAPF32.buffer, pointer, size);
const copiedBuffer = buffer.map(enhancementFunc);
return copiedBuffer;
};
const createGaussianCloudFromRaw = (wasmModule, raw) => {
return {
numPoints: raw.numPoints,
shDegree: raw.shDegree,
antialiased: raw.antialiased,
positions: floatVectorToFloatArray(wasmModule, raw.positions),
scales: floatVectorToFloatArray(wasmModule, raw.scales),
rotations: floatVectorToFloatArray(wasmModule, raw.rotations),
alphas: floatVectorToFloatArray(wasmModule, raw.alphas),
colors: floatVectorToFloatArray(wasmModule, raw.colors),
sh: floatVectorToFloatArray(wasmModule, raw.sh), // FIXME?
};
};
const disposeRawGSCloud = (wasmModule, raw) => {
wasmModule._free(wasmModule.vf32_ptr(raw.positions));
wasmModule._free(wasmModule.vf32_ptr(raw.scales));
wasmModule._free(wasmModule.vf32_ptr(raw.rotations));
wasmModule._free(wasmModule.vf32_ptr(raw.alphas));
wasmModule._free(wasmModule.vf32_ptr(raw.colors));
wasmModule._free(wasmModule.vf32_ptr(raw.sh));
};
class SpzSingleton {
static instance = null;
static loadingPromise = null;
static getInstance() {
if (this.instance) {
return Promise.resolve(this.instance);
}
if (!this.loadingPromise) {
this.loadingPromise = new Promise(async (resolve, reject) => {
try {
this.instance = await spzwasm();
console.log("spz.js: Spz::getInstance(): Wasm module loaded successfully");
resolve(this.instance);
} catch (err) {
console.error("spz.js: Spz::getInstance(): Error loading wasm module:", err);
reject(err);
}
});
}
return this.loadingPromise;
}
}
async function load(url) {
let pointer = null;
const instance = await SpzSingleton.getInstance();
console.log('spz.js: load(): Wasm instance loaded:', instance);
try {
// download byte array from url created in main thread
const response = await fetch(url);
if (!response.ok) {
throw new Error(`spz.js: load(): Failed to fetch data: ${response.status}`);
}
URL.revokeObjectURL(url);
const buffer = await response.arrayBuffer();
const spzData = new Uint8Array(buffer);
console.log('spz.js: load(): spzData.length=', spzData.length);
// let wasm allocate memory for spzData
pointer = instance._malloc(Uint8Array.BYTES_PER_ELEMENT * spzData.length);
if (pointer === null) {
throw new Error("spz.js: load(): couldn't allocate memory");
}
instance.HEAPU8.set(spzData, pointer / Uint8Array.BYTES_PER_ELEMENT);
// generate raw gaussian cloud from spzData
const rawGsCloud = instance.load_spz(pointer, spzData.length);
console.log('spz.js: load(): rawGsCloud.numPoints=', rawGsCloud.numPoints);
//console.log('spz.js: load(): rawGsCloud.shDegree=', rawGsCloud.shDegree);
//console.log('spz.js: load(): rawGsCloud.antialiased=', rawGsCloud.antialiased);
let options = null;
const gaussianCloud = createGaussianCloudFromRaw(instance, rawGsCloud, options);
disposeRawGSCloud(instance, rawGsCloud);
console.log('spz.js: load(): gaussianCloud.numPoints=', gaussianCloud.numPoints);
//console.log('spz.js: load(): gaussianCloud.shDegree=', gaussianCloud.shDegree);
//console.log('spz.js: load(): gaussianCloud.antialiased=', gaussianCloud.antialiased);
//console.log('spz.js: load(): gaussianCloud.positions.length=', gaussianCloud.positions.length);
//console.log('spz.js: load(): gaussianCloud.scales.length=', gaussianCloud.scales.length);
//console.log('spz.js: load(): gaussianCloud.rotations.length=', gaussianCloud.rotations.length);
//console.log('spz.js: load(): gaussianCloud.alphas.length=', gaussianCloud.alphas.length);
//console.log('spz.js: load(): gaussianCloud.colors.length=', gaussianCloud.colors.length);
//console.log('spz.js: load(): gaussianCloud.sh.length=', gaussianCloud.sh.length);
// Using transferable objects to avoid data copies
self.postMessage({
status: 'loaded',
gaussianCloud: {
numPoints: gaussianCloud.numPoints,
shDegree: gaussianCloud.shDegree,
antialiased: gaussianCloud.antialiased,
positions: gaussianCloud.positions.buffer,
scales: gaussianCloud.scales.buffer,
rotations: gaussianCloud.rotations.buffer,
alphas: gaussianCloud.alphas.buffer,
colors: gaussianCloud.colors.buffer,
sh: gaussianCloud.sh.buffer,
}
}, [
gaussianCloud.positions.buffer,
gaussianCloud.scales.buffer,
gaussianCloud.rotations.buffer,
gaussianCloud.alphas.buffer,
gaussianCloud.colors.buffer,
gaussianCloud.sh.buffer
]);
} catch (e) {
console.error(e);
} finally {
if (pointer !== null) {
instance._free(pointer);
console.log('spz.js: load(): done');
}
}
}
// Listen for messages from the main thread
self.addEventListener('message', async (e) => {
const { type, url } = e.data;
switch (type) {
case 'load':
await load(url);
break;
}
});