diff --git a/Cargo.lock b/Cargo.lock index 066c767..1f819b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,6 +51,26 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gl_matrix" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df64d0245c589931a0b5a385a63e7db2aeff209bdd471df0417e0f230a4c33ae" +dependencies = [ + "rand", +] + [[package]] name = "itoa" version = "1.0.11" @@ -66,6 +86,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + [[package]] name = "log" version = "0.4.21" @@ -116,6 +142,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.80" @@ -134,6 +166,47 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + [[package]] name = "random" version = "0.1.0" @@ -274,11 +347,18 @@ name = "utils" version = "0.1.0" dependencies = [ "console_error_panic_hook", + "gl_matrix", "serde", "serde_json", "wasm-bindgen", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasm-bindgen" version = "0.2.92" diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index 34740c0..ead4ea0 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -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" && diff --git a/app/src/lib/helpers/encode.test.ts b/app/src/lib/helpers/encode.test.ts index 6e99436..8813c61 100644 --- a/app/src/lib/helpers/encode.test.ts +++ b/app/src/lib/helpers/encode.test.ts @@ -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); }); diff --git a/app/src/lib/helpers/encode.ts b/app/src/lib/helpers/encode.ts index 49fd6b1..d5f77ab 100644 --- a/app/src/lib/helpers/encode.ts +++ b/app/src/lib/helpers/encode.ts @@ -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); } diff --git a/app/src/lib/runtime-executor.ts b/app/src/lib/runtime-executor.ts index b71f59d..5753a94 100644 --- a/app/src/lib/runtime-executor.ts +++ b/app/src/lib/runtime-executor.ts @@ -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; } diff --git a/app/src/lib/viewer/Scene.svelte b/app/src/lib/viewer/Scene.svelte new file mode 100644 index 0000000..83950c6 --- /dev/null +++ b/app/src/lib/viewer/Scene.svelte @@ -0,0 +1,24 @@ + + + + + + + + +{#each geometry as geo} + + + +{:else} + + + + +{/each} diff --git a/app/src/lib/viewer/Viewer.svelte b/app/src/lib/viewer/Viewer.svelte new file mode 100644 index 0000000..ddeda81 --- /dev/null +++ b/app/src/lib/viewer/Viewer.svelte @@ -0,0 +1,117 @@ + + + + + + + diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index a770278..fbf69f4 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -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) { 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 @@ - result: {res} -
- time: {time}ms +
{#key graph} diff --git a/nodes/max/plantarium/output/src/inputs.json b/nodes/max/plantarium/output/src/inputs.json index 16922a7..8399f1c 100644 --- a/nodes/max/plantarium/output/src/inputs.json +++ b/nodes/max/plantarium/output/src/inputs.json @@ -2,7 +2,7 @@ "outputs": [], "inputs": { "input": { - "type": "plant", + "type": "float", "external": true } } diff --git a/nodes/max/plantarium/output/src/lib.rs b/nodes/max/plantarium/output/src/lib.rs index 973d201..6212e04 100644 --- a/nodes/max/plantarium/output/src/lib.rs +++ b/nodes/max/plantarium/output/src/lib.rs @@ -1,16 +1,48 @@ use macros::include_definition_file; -use utils::evaluate_args; +use utils::{decode_float, encode_float}; use wasm_bindgen::prelude::*; +use web_sys::console; include_definition_file!("src/inputs.json"); +#[rustfmt::skip] #[wasm_bindgen] -pub fn execute(args: &[i32]) -> Vec { +pub fn execute(input: &[i32]) -> Vec { utils::set_panic_hook(); - // console::log_1(&format!("WASM(output_node): input: {:?}", args).into()); + let size = input[2]; + let decoded = decode_float(input[2]); + let negative_size = encode_float(-decoded); + + console::log_1(&format!("WASM(output_node): input: {:?} -> {}", input, decoded).into()); + + // [[1,3, x, y, z, x, y,z,x,y,z]]; + vec![ + 0, 1, // opening bracket + 0, 19, // opening bracket + distance to next bracket + 1, // 1: geometry + 3, // 3 vertices + 1, // 1 face + // thise are the indeces for the face + 0, 2, 1, + // this is the normal for the single face 1065353216 == 1.0f encoded is i32 + 0, 1065353216, 0, + // + negative_size, // x -> point 1 + 0, // y + 0, // z + // + size, // x -> point 2 + 0, // y + 0, // z + // + 0, // x -> point 3 + 0, // y + size, // z + // + 1, 1, 1, 1, // closing brackets + ] - evaluate_args(args) // let decoded = decode_float(result[0], result[1]); // console::log_1(&format!("WASM: output: {:?}", decoded).into()); diff --git a/nodes/max/plantarium/stem/src/lib.rs b/nodes/max/plantarium/stem/src/lib.rs index 49bf1f6..d9deefb 100644 --- a/nodes/max/plantarium/stem/src/lib.rs +++ b/nodes/max/plantarium/stem/src/lib.rs @@ -11,7 +11,7 @@ pub fn execute(input: &[i32]) -> Vec { let length = evaluate_args(args[0]); let thickness = evaluate_args(args[1]); - let resolution = evaluate_args(args[2]); + let resolution = 32; //evaluate_args(args[2]); console::log_1( &format!( @@ -21,14 +21,20 @@ pub fn execute(input: &[i32]) -> Vec { .into(), ); - let mut result: Vec = Vec::with_capacity(args.len() + 3); - - result.push(0); // encoding the [ bracket - result.push(2); - result.push(0); // adding the node-type, math: 0 - result.extend_from_slice(&thickness); - result.push(1); - result.push(1); // closing bracket - - result + vec![ + 0, // opening bracket + 11, // opening bracket + 0, // type: plant + 0, // alpha: 0 + 0, // x + 0, // y + 0, // z + 1, // thickness + 0, // x + 2, // y + 0, // z + 1, // thickness + 1, // closing bracket + 1, //closing bracket + ] } diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml index c4327ea..96928b5 100644 --- a/packages/utils/Cargo.toml +++ b/packages/utils/Cargo.toml @@ -11,3 +11,4 @@ wasm-bindgen = "0.2.92" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } console_error_panic_hook = { version = "0.1.7", optional = true } +gl_matrix = "0.0.2" diff --git a/packages/utils/src/encoding.rs b/packages/utils/src/encoding.rs index a6344fa..98ba5c3 100644 --- a/packages/utils/src/encoding.rs +++ b/packages/utils/src/encoding.rs @@ -1,16 +1,12 @@ -pub fn encode_float(f: f32) -> (i32, i32) { +pub fn encode_float(f: f32) -> i32 { + // Convert f32 to u32 using to_bits, then safely cast to i32 let bits = f.to_bits(); - let mantissa = (bits & 0x007FFFFF) as i32; - let exponent = ((bits >> 23) & 0xFF) as i32; - let sign = if f < 0.0 { 1 } else { 0 }; // Determine sign as 1 for negative, 0 for positive - (mantissa | (sign << 23), exponent) // Include the sign bit in the mantissa + bits as i32 } -pub fn decode_float(mantissa: i32, exponent: i32) -> f32 { - let sign_bit = ((mantissa >> 23) & 1) as u32; // Extract the sign bit - let mantissa_bits = (mantissa & 0x007FFFFF) as u32; - let exponent_bits = (exponent as u32 & 0xFF) << 23; - let bits = (sign_bit << 31) | exponent_bits | mantissa_bits; // Reconstruct all bits including sign +pub fn decode_float(bits: i32) -> f32 { + // Convert i32 to u32 safely, then use from_bits to get f32 + let bits = bits as u32; f32::from_bits(bits) } @@ -18,20 +14,24 @@ pub fn decode_float(mantissa: i32, exponent: i32) -> f32 { mod tests { use super::*; - #[rustfmt::skip] #[test] - fn test_encode_decode() { - let original_floats = [ - 0.0, 1.0, -1.0, 123.456, -123.456, 1e-10, -1e10, f32::MAX, f32::MIN, + fn test_decode_float_simple() { + let test_values: [f32; 6] = [ + 0.0, + -0.0, + 123.456, + -123.456, + std::f32::INFINITY, + std::f32::NEG_INFINITY, ]; - for &original in &original_floats { - let (mantissa, exponent) = encode_float(original); - let decoded = decode_float(mantissa, exponent); - assert!( - (decoded - original).abs() < 1e-6, - "Mismatch: original {} vs decoded {}", - original, - decoded + for &value in &test_values { + let encoded = encode_float(value); + let decoded = decode_float(encoded); + assert_eq!( + decoded.to_bits(), + value.to_bits(), + "Failed for value {}", + value ); } } diff --git a/packages/utils/src/geometry/extrude_path.rs b/packages/utils/src/geometry/extrude_path.rs new file mode 100644 index 0000000..9f257c2 --- /dev/null +++ b/packages/utils/src/geometry/extrude_path.rs @@ -0,0 +1,2 @@ +pub fn extrude_path(path: &[i32]) {} + diff --git a/packages/utils/src/nodes.rs b/packages/utils/src/nodes.rs index d69beee..cf3d203 100644 --- a/packages/utils/src/nodes.rs +++ b/packages/utils/src/nodes.rs @@ -1,10 +1,10 @@ use crate::encoding; -pub fn math_node(args: &[i32]) -> (i32, i32) { +pub fn math_node(args: &[i32]) -> i32 { let math_type = args[0]; - let a = encoding::decode_float(args[1], args[2]); - let b = encoding::decode_float(args[3], args[4]); + let a = encoding::decode_float(args[1]); + let b = encoding::decode_float(args[2]); let result = match math_type { 0 => a + b, diff --git a/packages/utils/src/tree.rs b/packages/utils/src/tree.rs index 134e50f..a931a4d 100644 --- a/packages/utils/src/tree.rs +++ b/packages/utils/src/tree.rs @@ -57,12 +57,12 @@ pub fn get_args(args: &[i32]) -> Vec<&[i32]> { out_args } -pub fn evaluate_node(input_args: &[i32]) -> (i32, i32) { +pub fn evaluate_node(input_args: &[i32]) -> i32 { let node_type = input_args[0]; match node_type { 0 => crate::nodes::math_node(&input_args[1..]), - _ => (0, 0), + _ => 0, } } @@ -92,7 +92,7 @@ pub fn evaluate_args(input_args: &[i32]) -> Vec { if resolved.len() > 1 { let res = evaluate_node(&resolved); - vec![res.0, res.1] + vec![res] } else { resolved } @@ -112,7 +112,7 @@ mod tests { // the numbers are f32 floats encoded as two i32's let result = evaluate_args(&input); - let decoded = decode_float(result[0], result[1]); + let decoded = decode_float(result[0]); assert_eq!(decoded, 6.0); }