feat: yaaay a triangle :)))
This commit is contained in:
@ -403,8 +403,6 @@
|
||||
function handleMouseDown(event: MouseEvent) {
|
||||
if (mouseDown) return;
|
||||
|
||||
console.log(event.target);
|
||||
|
||||
if (event.target instanceof HTMLElement) {
|
||||
if (
|
||||
event.target.nodeName !== "CANVAS" &&
|
||||
|
@ -4,7 +4,7 @@ import { encodeFloat, decodeFloat } from "./encode"
|
||||
test("encode_float", () => {
|
||||
const input = 1.23;
|
||||
const encoded = encodeFloat(input)
|
||||
const output = decodeFloat(encoded[0], encoded[1])
|
||||
const output = decodeFloat(encoded)
|
||||
console.log(input, output)
|
||||
expect(output).toBeCloseTo(input);
|
||||
});
|
||||
@ -12,7 +12,7 @@ test("encode_float", () => {
|
||||
test("encode 2.0", () => {
|
||||
const input = 2.0;
|
||||
const encoded = encodeFloat(input)
|
||||
expect(encoded).toEqual([0, 128])
|
||||
expect(encoded).toEqual(1073741824)
|
||||
});
|
||||
|
||||
test("floating point imprecision", () => {
|
||||
@ -20,7 +20,7 @@ test("floating point imprecision", () => {
|
||||
new Array(10_000).fill(null).forEach((_, i) => {
|
||||
const input = i < 5_000 ? i : Math.random() * 100;
|
||||
const encoded = encodeFloat(input);
|
||||
const output = decodeFloat(encoded[0], encoded[1]);
|
||||
const output = decodeFloat(encoded);
|
||||
|
||||
const error = Math.abs(input - output);
|
||||
if (error > maxError) {
|
||||
@ -36,7 +36,7 @@ test("negative numbers", () => {
|
||||
const inputs = [-1, -0.5, -123.456, -0.0001];
|
||||
inputs.forEach(input => {
|
||||
const encoded = encodeFloat(input);
|
||||
const output = decodeFloat(encoded[0], encoded[1]);
|
||||
const output = decodeFloat(encoded);
|
||||
expect(output).toBeCloseTo(input);
|
||||
});
|
||||
});
|
||||
@ -45,7 +45,7 @@ test("negative numbers", () => {
|
||||
test("very small numbers", () => {
|
||||
const input = 1.2345e-38;
|
||||
const encoded = encodeFloat(input)
|
||||
const output = decodeFloat(encoded[0], encoded[1])
|
||||
const output = decodeFloat(encoded)
|
||||
expect(output).toBeCloseTo(input);
|
||||
});
|
||||
|
||||
@ -53,7 +53,7 @@ test("very small numbers", () => {
|
||||
test("zero", () => {
|
||||
const input = 0;
|
||||
const encoded = encodeFloat(input)
|
||||
const output = decodeFloat(encoded[0], encoded[1])
|
||||
const output = decodeFloat(encoded)
|
||||
expect(output).toBe(0);
|
||||
});
|
||||
|
||||
@ -61,7 +61,7 @@ test("zero", () => {
|
||||
test("infinity", () => {
|
||||
const input = Infinity;
|
||||
const encoded = encodeFloat(input)
|
||||
const output = decodeFloat(encoded[0], encoded[1])
|
||||
const output = decodeFloat(encoded)
|
||||
expect(output).toBe(Infinity);
|
||||
});
|
||||
|
||||
@ -70,7 +70,7 @@ test("large numbers", () => {
|
||||
const inputs = [1e+5, 1e+10];
|
||||
inputs.forEach(input => {
|
||||
const encoded = encodeFloat(input);
|
||||
const output = decodeFloat(encoded[0], encoded[1]);
|
||||
const output = decodeFloat(encoded);
|
||||
// Note: Large numbers may lose precision, hence using toBeCloseTo with a tolerance
|
||||
expect(output).toBeCloseTo(input, 0);
|
||||
});
|
||||
|
@ -1,34 +1,19 @@
|
||||
// Create a buffer to hold the float as bytes
|
||||
const buffer = new ArrayBuffer(4);
|
||||
const view = new DataView(buffer);
|
||||
|
||||
export function encodeFloat(f: number): [number, number] {
|
||||
let buffer = new ArrayBuffer(4); // Create a buffer of 4 bytes (32 bits)
|
||||
let floatView = new Float32Array(buffer);
|
||||
let intView = new Uint32Array(buffer);
|
||||
export function encodeFloat(value: number): number {
|
||||
// Write the number as a float to the buffer
|
||||
view.setFloat32(0, value, true); // 'true' for little-endian
|
||||
|
||||
floatView[0] = f; // Store the float into the buffer
|
||||
let bits = intView[0]; // Read the bits as integer
|
||||
|
||||
let mantissa = bits & 0x007FFFFF;
|
||||
let exponent = (bits >> 23) & 0xFF;
|
||||
let sign = (f < 0.0) ? 1 : 0;
|
||||
|
||||
// Include the sign bit in the mantissa
|
||||
mantissa = mantissa | (sign << 23);
|
||||
|
||||
return [mantissa, exponent];
|
||||
// Read the buffer as an integer
|
||||
return view.getInt32(0, true);
|
||||
}
|
||||
|
||||
export function decodeFloat(mantissa: number, exponent: number): number {
|
||||
let signBit = (mantissa >> 23) & 1;
|
||||
let mantissaBits = mantissa & 0x007FFFFF;
|
||||
let exponentBits = (exponent & 0xFF) << 23;
|
||||
export function decodeFloat(value: number): number {
|
||||
// Write the integer back as an int32
|
||||
view.setInt32(0, value, true);
|
||||
|
||||
// Reconstruct all bits including sign
|
||||
let bits = (signBit << 31) | exponentBits | mantissaBits;
|
||||
|
||||
let buffer = new ArrayBuffer(4);
|
||||
let floatView = new Float32Array(buffer);
|
||||
let intView = new Uint32Array(buffer);
|
||||
|
||||
intView[0] = bits; // Set the bits as integer
|
||||
return floatView[0]; // Read the float back from the buffer
|
||||
// Read the buffer as a float
|
||||
return view.getFloat32(0, true);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "@nodes/types";
|
||||
import { encodeFloat } from "./helpers/encode";
|
||||
import { concat_encoded, encode } from "./helpers/flat_tree";
|
||||
import { fastHash, fastHashString } from "./helpers/fastHash";
|
||||
import { concat_encoded } from "./helpers/flat_tree";
|
||||
import { fastHash } from "./helpers/fastHash";
|
||||
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
||||
}
|
||||
|
||||
if (input_type.type === "float") {
|
||||
return encode(encodeFloat(value as number));
|
||||
return encodeFloat(value as number);
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -208,9 +208,9 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
||||
}
|
||||
|
||||
// return the result of the parent of the output node
|
||||
const res = results[outputNode.id] as string
|
||||
const res = results[outputNode.id];
|
||||
|
||||
return res;
|
||||
return res as unknown as Int32Array;
|
||||
|
||||
}
|
||||
|
||||
|
24
app/src/lib/viewer/Scene.svelte
Normal file
24
app/src/lib/viewer/Scene.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { T } from "@threlte/core";
|
||||
import type { BufferGeometry } from "three";
|
||||
import { OrbitControls } from "@threlte/extras";
|
||||
|
||||
export let geometry: BufferGeometry[];
|
||||
</script>
|
||||
|
||||
<T.PerspectiveCamera position={[10, 10, 10]} makeDefault fov={50}>
|
||||
<OrbitControls />
|
||||
</T.PerspectiveCamera>
|
||||
|
||||
<T.DirectionalLight position={[0, 10, 10]} />
|
||||
|
||||
{#each geometry as geo}
|
||||
<T.Mesh geometry={geo}>
|
||||
<T.MeshBasicMaterial color="red" />
|
||||
</T.Mesh>
|
||||
{:else}
|
||||
<T.Mesh>
|
||||
<T.BoxGeometry args={[1, 1, 1]} />
|
||||
<T.MeshStandardMaterial color="hotpink" />
|
||||
</T.Mesh>
|
||||
{/each}
|
117
app/src/lib/viewer/Viewer.svelte
Normal file
117
app/src/lib/viewer/Viewer.svelte
Normal file
@ -0,0 +1,117 @@
|
||||
<script lang="ts">
|
||||
import { Canvas } from "@threlte/core";
|
||||
import Scene from "./Scene.svelte";
|
||||
import { BufferGeometry, Float32BufferAttribute } from "three";
|
||||
import { decodeFloat } from "$lib/helpers/encode";
|
||||
|
||||
export let result: Int32Array;
|
||||
|
||||
let geometries: BufferGeometry[] = [];
|
||||
|
||||
function createGeometryFromEncodedData(
|
||||
encodedData: Int32Array,
|
||||
): BufferGeometry {
|
||||
const geometry = new BufferGeometry();
|
||||
|
||||
// Extract data from the encoded array
|
||||
let index = 0;
|
||||
const geometryType = encodedData[index++];
|
||||
const vertexCount = encodedData[index++];
|
||||
const faceCount = encodedData[index++];
|
||||
|
||||
// Indices
|
||||
const indices: number[] = [];
|
||||
for (let i = 0; i < faceCount * 3; i++) {
|
||||
indices.push(encodedData[index++]);
|
||||
}
|
||||
|
||||
// Face normals (although typically there would be one normal per vertex)
|
||||
const normals: number[] = [];
|
||||
for (let i = 0; i < faceCount; i++) {
|
||||
const x = decodeFloat(encodedData[index++]);
|
||||
const y = decodeFloat(encodedData[index++]);
|
||||
const z = decodeFloat(encodedData[index++]);
|
||||
normals.push(x, y, z);
|
||||
}
|
||||
|
||||
// Vertices
|
||||
const vertices: number[] = [];
|
||||
for (let i = 0; i < vertexCount; i++) {
|
||||
const x = decodeFloat(encodedData[index++]);
|
||||
const y = decodeFloat(encodedData[index++]);
|
||||
const z = decodeFloat(encodedData[index++]);
|
||||
vertices.push(x, y, z);
|
||||
}
|
||||
|
||||
// Add data to geometry
|
||||
geometry.setIndex(indices);
|
||||
geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
|
||||
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
$: if (result) {
|
||||
const inputs = parse_args(result);
|
||||
|
||||
console.log({ inputs });
|
||||
|
||||
for (let input of inputs) {
|
||||
if (input[0] === 1) {
|
||||
const geo = createGeometryFromEncodedData(input);
|
||||
geometries = [geo];
|
||||
console.log(geo);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Canvas>
|
||||
<Scene geometry={geometries} />
|
||||
</Canvas>
|
||||
|
||||
<style>
|
||||
</style>
|
@ -6,15 +6,18 @@
|
||||
import * as templates from "$lib/graph-templates";
|
||||
import type { Graph } from "@nodes/types";
|
||||
import { decode, encode } from "$lib/helpers/flat_tree";
|
||||
import { decodeFloat } from "$lib/helpers/encode";
|
||||
import { decodeFloat, encodeFloat } from "$lib/helpers/encode";
|
||||
import Viewer from "$lib/viewer/Viewer.svelte";
|
||||
|
||||
globalThis.decode = decode;
|
||||
globalThis.encode = encode;
|
||||
globalThis.df = decodeFloat;
|
||||
globalThis.en = encodeFloat;
|
||||
|
||||
const nodeRegistry = new RemoteNodeRegistry("http://localhost:3001");
|
||||
const runtimeExecutor = new MemoryRuntimeExecutor(nodeRegistry);
|
||||
|
||||
let res = "2";
|
||||
let res: Int32Array;
|
||||
let time = 0;
|
||||
|
||||
let graph = localStorage.getItem("graph")
|
||||
@ -23,13 +26,7 @@
|
||||
|
||||
function handleResult(event: CustomEvent<Graph>) {
|
||||
let a = performance.now();
|
||||
let _res: any = runtimeExecutor.execute(event.detail);
|
||||
if (_res instanceof Int32Array) {
|
||||
const f = decodeFloat(_res[0], _res[1]);
|
||||
res = Math.round(f * 100_000) / 100_000;
|
||||
} else {
|
||||
res = _res;
|
||||
}
|
||||
res = runtimeExecutor.execute(event.detail);
|
||||
time = performance.now() - a;
|
||||
console.log(res);
|
||||
}
|
||||
@ -50,9 +47,7 @@
|
||||
</header>
|
||||
<Grid.Row>
|
||||
<Grid.Cell>
|
||||
result: {res}
|
||||
<br />
|
||||
time: {time}ms
|
||||
<Viewer result={res} />
|
||||
</Grid.Cell>
|
||||
<Grid.Cell>
|
||||
{#key graph}
|
||||
|
Reference in New Issue
Block a user