Some checks failed
Deploy to GitHub Pages / build_site (push) Failing after 1m21s
215 lines
5.4 KiB
Svelte
215 lines
5.4 KiB
Svelte
<script lang="ts">
|
|
import { Canvas } from "@threlte/core";
|
|
import Scene from "./Scene.svelte";
|
|
import {
|
|
BufferAttribute,
|
|
BufferGeometry,
|
|
Float32BufferAttribute,
|
|
Vector3,
|
|
} from "three";
|
|
import { decodeFloat, fastHashArrayBuffer } from "@nodes/utils";
|
|
import type { PerformanceStore } from "$lib/performance";
|
|
import { AppSettings } from "$lib/settings/app-settings";
|
|
|
|
export let centerCamera: boolean = true;
|
|
export let perf: PerformanceStore;
|
|
|
|
let geometries: BufferGeometry[] = [];
|
|
let lines: Vector3[][] = [];
|
|
|
|
let totalVertices = 0;
|
|
let totalFaces = 0;
|
|
|
|
function fastArrayHash(arr: ArrayBuffer) {
|
|
let ints = new Uint8Array(arr);
|
|
|
|
const sampleDistance = Math.max(Math.floor(ints.length / 100), 1);
|
|
const sampleCount = Math.floor(ints.length / sampleDistance);
|
|
|
|
let hash = new Uint8Array(sampleCount);
|
|
|
|
for (let i = 0; i < sampleCount; i++) {
|
|
const index = i * sampleDistance;
|
|
hash[i] = ints[index];
|
|
}
|
|
|
|
return fastHashArrayBuffer(hash.buffer);
|
|
}
|
|
|
|
function createGeometryFromEncodedData(
|
|
encodedData: Int32Array,
|
|
geometry = new BufferGeometry(),
|
|
): BufferGeometry {
|
|
// Extract data from the encoded array
|
|
let index = 0;
|
|
const geometryType = encodedData[index++];
|
|
const vertexCount = encodedData[index++];
|
|
const faceCount = encodedData[index++];
|
|
|
|
totalVertices += vertexCount;
|
|
totalFaces += faceCount;
|
|
|
|
// Indices
|
|
const indicesEnd = index + faceCount * 3;
|
|
const indices = encodedData.subarray(index, indicesEnd);
|
|
index = indicesEnd;
|
|
|
|
// Vertices
|
|
const vertices = new Float32Array(
|
|
encodedData.buffer,
|
|
index * 4,
|
|
vertexCount * 3,
|
|
);
|
|
index = index + vertexCount * 3;
|
|
let hash = fastArrayHash(vertices);
|
|
if (geometry.userData?.hash === hash) {
|
|
return geometry;
|
|
}
|
|
|
|
const normals = new Float32Array(
|
|
encodedData.buffer,
|
|
index * 4,
|
|
vertexCount * 3,
|
|
);
|
|
index = index + vertexCount * 3;
|
|
|
|
if (
|
|
geometry.userData?.faceCount !== faceCount ||
|
|
geometry.userData?.vertexCount !== vertexCount
|
|
) {
|
|
// Add data to geometry
|
|
geometry.setIndex([...indices]);
|
|
}
|
|
|
|
let posAttribute = geometry.getAttribute(
|
|
"position",
|
|
) as BufferAttribute | null;
|
|
|
|
if (posAttribute && posAttribute.count === vertexCount) {
|
|
posAttribute.set(vertices, 0);
|
|
posAttribute.needsUpdate = true;
|
|
} else {
|
|
geometry.setAttribute(
|
|
"position",
|
|
new Float32BufferAttribute(vertices, 3),
|
|
);
|
|
}
|
|
|
|
const normalsAttribute = geometry.getAttribute(
|
|
"normal",
|
|
) as BufferAttribute | null;
|
|
if (normalsAttribute && normalsAttribute.count === vertexCount) {
|
|
normalsAttribute.set(normals, 0);
|
|
normalsAttribute.needsUpdate = true;
|
|
} else {
|
|
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
|
|
}
|
|
|
|
geometry.userData = {
|
|
vertexCount,
|
|
faceCount,
|
|
hash,
|
|
};
|
|
|
|
return geometry;
|
|
}
|
|
|
|
function parse_args(input: Int32Array) {
|
|
let index = 0;
|
|
const length = input.length;
|
|
let res: Int32Array[] = [];
|
|
|
|
let nextBracketIndex = 0;
|
|
let argStartIndex = 0;
|
|
let depth = -1;
|
|
|
|
while (index < length) {
|
|
const value = input[index];
|
|
|
|
if (index === nextBracketIndex) {
|
|
nextBracketIndex = index + input[index + 1] + 1;
|
|
if (value === 0) {
|
|
depth++;
|
|
} else {
|
|
depth--;
|
|
}
|
|
|
|
if (depth === 1 && value === 0) {
|
|
// if opening bracket
|
|
argStartIndex = index + 2;
|
|
}
|
|
|
|
if (depth === 0 && value === 1) {
|
|
// if closing bracket
|
|
res.push(input.slice(argStartIndex, index));
|
|
argStartIndex = index + 2;
|
|
}
|
|
|
|
index = nextBracketIndex;
|
|
continue;
|
|
}
|
|
|
|
// we should not be here
|
|
|
|
index++;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
function createLineGeometryFromEncodedData(encodedData: Int32Array) {
|
|
const positions: Vector3[] = [];
|
|
|
|
const amount = (encodedData.length - 1) / 4;
|
|
|
|
for (let i = 0; i < amount; i++) {
|
|
const x = decodeFloat(encodedData[2 + i * 4 + 0]);
|
|
const y = decodeFloat(encodedData[2 + i * 4 + 1]);
|
|
const z = decodeFloat(encodedData[2 + i * 4 + 2]);
|
|
positions.push(new Vector3(x, y, z));
|
|
}
|
|
|
|
return positions;
|
|
}
|
|
|
|
export const update = function updateGeometries(result: Int32Array) {
|
|
let a = performance.now();
|
|
const inputs = parse_args(result);
|
|
let b = performance.now();
|
|
perf?.addPoint("split-result", b - a);
|
|
|
|
totalVertices = 0;
|
|
totalFaces = 0;
|
|
|
|
if ($AppSettings.showStemLines) {
|
|
a = performance.now();
|
|
lines = inputs
|
|
.map((input) => {
|
|
if (input[0] === 0) {
|
|
return createLineGeometryFromEncodedData(input);
|
|
}
|
|
})
|
|
.filter(Boolean) as Vector3[][];
|
|
b = performance.now();
|
|
perf?.addPoint("create-lines", b - a);
|
|
}
|
|
|
|
a = performance.now();
|
|
geometries = inputs
|
|
.map((input, i) => {
|
|
if (input[0] === 1) {
|
|
return createGeometryFromEncodedData(input, geometries[i]);
|
|
}
|
|
})
|
|
.filter(Boolean) as BufferGeometry[];
|
|
b = performance.now();
|
|
perf?.addPoint("create-geometries", b - a);
|
|
perf?.addPoint("total-vertices", totalVertices);
|
|
perf?.addPoint("total-faces", totalFaces);
|
|
};
|
|
</script>
|
|
|
|
<Canvas>
|
|
<Scene {geometries} {lines} {centerCamera} />
|
|
</Canvas>
|