From 2de2560a57904d070053f91b8d6d166d8dd83511 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Wed, 24 Apr 2024 22:16:15 +0200 Subject: [PATCH] feat: implement branch node (almost finsihed) --- Cargo.lock | 45 ++----- app/src/lib/result-viewer/Scene.svelte | 10 +- app/src/lib/settings/panels/ActiveNode.svelte | 16 ++- app/src/routes/+page.svelte | 59 +++++---- nodes/max/plantarium/array/src/input.json | 16 --- nodes/max/plantarium/array/src/lib.rs | 30 ----- nodes/max/plantarium/box/src/lib.rs | 4 +- .../plantarium/{array => branch}/.gitignore | 0 .../plantarium/{array => branch}/Cargo.toml | 5 +- .../plantarium/{array => branch}/package.json | 0 .../{branches => branch}/src/input.json | 4 +- nodes/max/plantarium/branch/src/lib.rs | 116 +++++++++++++++++ .../plantarium/{array => branch}/tests/web.rs | 0 nodes/max/plantarium/branches/.gitignore | 6 - nodes/max/plantarium/branches/Cargo.toml | 28 ---- nodes/max/plantarium/branches/package.json | 6 - nodes/max/plantarium/branches/src/lib.rs | 18 --- nodes/max/plantarium/branches/tests/web.rs | 13 -- nodes/max/plantarium/math/src/lib.rs | 4 +- nodes/max/plantarium/noise/src/input.json | 7 + nodes/max/plantarium/noise/src/lib.rs | 24 +++- nodes/max/plantarium/output/src/lib.rs | 13 +- nodes/max/plantarium/random/src/lib.rs | 4 +- nodes/max/plantarium/stem/src/lib.rs | 4 +- nodes/max/plantarium/sum/.gitignore | 6 - nodes/max/plantarium/sum/Cargo.toml | 28 ---- nodes/max/plantarium/sum/package.json | 6 - nodes/max/plantarium/sum/src/input.json | 13 -- nodes/max/plantarium/sum/src/lib.rs | 27 ---- nodes/max/plantarium/sum/tests/web.rs | 13 -- nodes/max/plantarium/triangle/src/lib.rs | 4 +- nodes/max/plantarium/vec3/src/lib.rs | 4 +- packages/utils/src/geometry/geometry_data.rs | 10 +- packages/utils/src/geometry/path_data.rs | 123 ++++++++++++++++-- packages/utils/src/tree.rs | 68 +++++++--- 35 files changed, 396 insertions(+), 338 deletions(-) delete mode 100644 nodes/max/plantarium/array/src/input.json delete mode 100644 nodes/max/plantarium/array/src/lib.rs rename nodes/max/plantarium/{array => branch}/.gitignore (100%) rename nodes/max/plantarium/{array => branch}/Cargo.toml (96%) rename nodes/max/plantarium/{array => branch}/package.json (100%) rename nodes/max/plantarium/{branches => branch}/src/input.json (96%) create mode 100644 nodes/max/plantarium/branch/src/lib.rs rename nodes/max/plantarium/{array => branch}/tests/web.rs (100%) delete mode 100644 nodes/max/plantarium/branches/.gitignore delete mode 100644 nodes/max/plantarium/branches/Cargo.toml delete mode 100644 nodes/max/plantarium/branches/package.json delete mode 100644 nodes/max/plantarium/branches/src/lib.rs delete mode 100644 nodes/max/plantarium/branches/tests/web.rs delete mode 100644 nodes/max/plantarium/sum/.gitignore delete mode 100644 nodes/max/plantarium/sum/Cargo.toml delete mode 100644 nodes/max/plantarium/sum/package.json delete mode 100644 nodes/max/plantarium/sum/src/input.json delete mode 100644 nodes/max/plantarium/sum/src/lib.rs delete mode 100644 nodes/max/plantarium/sum/tests/web.rs diff --git a/Cargo.lock b/Cargo.lock index 6302ff8..7e07be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,13 @@ version = 3 [[package]] -name = "array" +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "box" version = "0.1.0" dependencies = [ "console_error_panic_hook", @@ -17,16 +23,11 @@ dependencies = [ ] [[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "box" +name = "branch" version = "0.1.0" dependencies = [ "console_error_panic_hook", + "glam", "macros", "serde", "serde-wasm-bindgen", @@ -123,20 +124,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "max-plantarium-sum" -version = "0.1.0" -dependencies = [ - "console_error_panic_hook", - "macros", - "serde", - "serde-wasm-bindgen", - "utils", - "wasm-bindgen", - "wasm-bindgen-test", - "web-sys", -] - [[package]] name = "max-plantarium-triangle" version = "0.1.0" @@ -367,20 +354,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "template" -version = "0.1.0" -dependencies = [ - "console_error_panic_hook", - "macros", - "serde", - "serde-wasm-bindgen", - "utils", - "wasm-bindgen", - "wasm-bindgen-test", - "web-sys", -] - [[package]] name = "types" version = "0.1.0" diff --git a/app/src/lib/result-viewer/Scene.svelte b/app/src/lib/result-viewer/Scene.svelte index 99f228f..4ca8879 100644 --- a/app/src/lib/result-viewer/Scene.svelte +++ b/app/src/lib/result-viewer/Scene.svelte @@ -7,7 +7,6 @@ useTexture, } from "@threlte/extras"; import { - Texture, type BufferGeometry, type PerspectiveCamera, type Vector3, @@ -16,7 +15,6 @@ import { OrbitControls } from "@threlte/extras"; import { AppSettings } from "../settings/app-settings"; import localStore from "$lib/helpers/localStore"; - import { Inspector } from "three-inspect"; export let geometries: BufferGeometry[]; export let lines: Vector3[][]; @@ -89,13 +87,9 @@ {/if} {#await matcap then value} - + {#if false} - + {/if} {/await} diff --git a/app/src/lib/settings/panels/ActiveNode.svelte b/app/src/lib/settings/panels/ActiveNode.svelte index a0a5d1e..531fb97 100644 --- a/app/src/lib/settings/panels/ActiveNode.svelte +++ b/app/src/lib/settings/panels/ActiveNode.svelte @@ -64,11 +64,17 @@ {#if node} - {#if nodeDefinition && store && Object.keys(nodeDefinition).length > 0} - - {:else} -

Active Node has no Settings

- {/if} + {#key node.id} + {#if nodeDefinition && store && Object.keys(nodeDefinition).length > 0} + + {:else} +

Active Node has no Settings

+ {/if} + {/key} {:else}

No active node

{/if} diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 47c8f99..850eff3 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -49,10 +49,25 @@ let keymap: ReturnType; function handleResult(event: CustomEvent) { - res = runtimeExecutor.execute(event.detail, get(settings?.graph?.settings)); + try { + res = runtimeExecutor.execute( + event.detail, + get(settingPanels?.graph?.settings), + ); + } catch (error) { + console.log("errors", error); + } if ($AppSettings.centerCamera && viewerCamera && viewerCenter) { - viewerControls.target.copy(viewerCenter); + if ( + Number.isNaN(viewerCenter.x) || + Number.isNaN(viewerCenter.y) || + Number.isNaN(viewerCenter.z) + ) { + // viewerCenter.set(0, 0, 0); + } else { + viewerControls.target.copy(viewerCenter); + } viewerControls.update(); } } @@ -61,7 +76,7 @@ localStorage.setItem("graph", JSON.stringify(event.detail)); } - let settings: Record = { + let settingPanels: Record = { general: { id: "general", icon: "i-tabler-settings", @@ -90,33 +105,33 @@ }; $: if (keymap) { - settings.shortcuts = { + settingPanels.shortcuts = { id: "shortcuts", icon: "i-tabler-keyboard", props: { keymap }, component: Keymap, }; - settings = settings; + settingPanels = settingPanels; } $: if (manager) { - settings.activeNode.props.manager = manager; - settings.nodeStore = { + settingPanels.activeNode.props.manager = manager; + settingPanels.nodeStore = { id: "Node Store", icon: "i-tabler-database", props: { nodeRegistry, manager }, component: NodeStore, }; - settings = settings; + settingPanels = settingPanels; } $: if (activeNode) { - settings.activeNode.props.node = activeNode; - settings = settings; + settingPanels.activeNode.props.node = activeNode; + settingPanels = settingPanels; } else { - settings.activeNode.props.node = undefined; - settings = settings; + settingPanels.activeNode.props.node = undefined; + settingPanels = settingPanels; } function handleSettings( @@ -125,25 +140,25 @@ types: Record; }>, ) { - settings.general.definition.debug.stressTest.loadGrid.callback = + settingPanels.general.definition.debug.stressTest.loadGrid.callback = function () { - const store = get(settings.general.settings); + const store = get(settingPanels.general.settings); graph = templates.grid(store.amount, store.amount); }; - settings.general.definition.debug.stressTest.loadTree.callback = + settingPanels.general.definition.debug.stressTest.loadTree.callback = function () { - const store = get(settings.general.settings); + const store = get(settingPanels.general.settings); graph = templates.tree(store.amount); }; - settings.graph.settings = writable(ev.detail.values); - settings.graph.definition = { - ...settings.graph.definition, + settingPanels.graph.settings = writable(ev.detail.values); + settingPanels.graph.definition = { + ...settingPanels.graph.definition, ...ev.detail.types, }; - settings = settings; + settingPanels = settingPanels; } @@ -168,12 +183,12 @@ bind:keymap showGrid={$AppSettings?.showNodeGrid} snapToGrid={$AppSettings?.snapToGrid} - settings={settings?.graph?.settings} + settings={settingPanels?.graph?.settings} on:settings={handleSettings} on:result={handleResult} on:save={handleSave} /> - + {/key} diff --git a/nodes/max/plantarium/array/src/input.json b/nodes/max/plantarium/array/src/input.json deleted file mode 100644 index 27cf31a..0000000 --- a/nodes/max/plantarium/array/src/input.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "max/plantarium/array", - "outputs": [ - "float" - ], - "inputs": { - "value": { - "type": "float", - "value": 4.2 - }, - "amount": { - "type": "integer", - "value": 2 - } - } -} diff --git a/nodes/max/plantarium/array/src/lib.rs b/nodes/max/plantarium/array/src/lib.rs deleted file mode 100644 index 01f0158..0000000 --- a/nodes/max/plantarium/array/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -use macros::include_definition_file; -use utils::{evaluate_int, get_args}; -use wasm_bindgen::prelude::*; -use web_sys::console; - -include_definition_file!("src/input.json"); - -#[wasm_bindgen] -pub fn execute(input: &[i32]) -> Vec { - utils::set_panic_hook(); - - let args = get_args(input); - - let value_encoded = evaluate_int(args[0]); - let length = evaluate_int(args[1]) as usize; - - console::log_1(&format!("WASM(array): input: {:?} -> {:?}", args, value_encoded).into()); - - // construct array of length - let mut res: Vec = Vec::with_capacity(length + 4); - res.push(0); - res.push(length as i32 + 4); - for _ in 0..length { - res.push(value_encoded); - } - res.push(1); - res.push(1); - - res -} diff --git a/nodes/max/plantarium/box/src/lib.rs b/nodes/max/plantarium/box/src/lib.rs index 5183167..954edc0 100644 --- a/nodes/max/plantarium/box/src/lib.rs +++ b/nodes/max/plantarium/box/src/lib.rs @@ -1,6 +1,6 @@ use macros::include_definition_file; use utils::{ - encode_float, evaluate_float, geometry::calculate_normals, get_args, set_panic_hook, wrap_arg, + encode_float, evaluate_float, geometry::calculate_normals, set_panic_hook, split_args, wrap_arg, }; use wasm_bindgen::prelude::*; use web_sys::console; @@ -13,7 +13,7 @@ pub fn execute(input: &[i32]) -> Vec { set_panic_hook(); - let args = get_args(input); + let args = split_args(input); console::log_1(&format!("WASM(cube): input: {:?} -> {:?}", input, args ).into()); diff --git a/nodes/max/plantarium/array/.gitignore b/nodes/max/plantarium/branch/.gitignore similarity index 100% rename from nodes/max/plantarium/array/.gitignore rename to nodes/max/plantarium/branch/.gitignore diff --git a/nodes/max/plantarium/array/Cargo.toml b/nodes/max/plantarium/branch/Cargo.toml similarity index 96% rename from nodes/max/plantarium/array/Cargo.toml rename to nodes/max/plantarium/branch/Cargo.toml index 7387ce3..a2f94b1 100644 --- a/nodes/max/plantarium/array/Cargo.toml +++ b/nodes/max/plantarium/branch/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "array" +name = "branch" version = "0.1.0" authors = ["Max Richter "] edition = "2018" @@ -19,10 +19,11 @@ wasm-bindgen = "0.2.84" # code size when deploying. utils = { version = "0.1.0", path = "../../../../packages/utils" } macros = { version = "0.1.0", path = "../../../../packages/macros" } -web-sys = { version = "0.3.69", features = ["console"] } serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.4" console_error_panic_hook = { version = "0.1.7", optional = true } +web-sys = { version = "0.3.69", features = ["console"] } +glam = "0.27.0" [dev-dependencies] wasm-bindgen-test = "0.3.34" diff --git a/nodes/max/plantarium/array/package.json b/nodes/max/plantarium/branch/package.json similarity index 100% rename from nodes/max/plantarium/array/package.json rename to nodes/max/plantarium/branch/package.json diff --git a/nodes/max/plantarium/branches/src/input.json b/nodes/max/plantarium/branch/src/input.json similarity index 96% rename from nodes/max/plantarium/branches/src/input.json rename to nodes/max/plantarium/branch/src/input.json index e7e4eba..74cc454 100644 --- a/nodes/max/plantarium/branches/src/input.json +++ b/nodes/max/plantarium/branch/src/input.json @@ -15,7 +15,7 @@ "step": 0.05, "value": 0.8 }, - "thiccness": { + "thickness": { "type": "float", "min": 0, "max": 1, @@ -47,7 +47,7 @@ "value": 1 }, "depth": { - "type": "float", + "type": "integer", "hidden": true, "min": 1, "value": 1, diff --git a/nodes/max/plantarium/branch/src/lib.rs b/nodes/max/plantarium/branch/src/lib.rs new file mode 100644 index 0000000..30b5b46 --- /dev/null +++ b/nodes/max/plantarium/branch/src/lib.rs @@ -0,0 +1,116 @@ +use std::f32::consts::PI; + +use glam::Vec3; +use macros::include_definition_file; +use utils::{ + concat_arg_vecs, evaluate_float, evaluate_int, + geometry::{create_path, get_direction_at_path, get_point_at_path, wrap_path, wrap_path_mut}, + log, set_panic_hook, split_args, +}; +use wasm_bindgen::prelude::*; + +include_definition_file!("src/input.json"); + +#[wasm_bindgen] +pub fn execute(input: &[i32]) -> Vec { + set_panic_hook(); + + let args = split_args(input); + + let paths = split_args(args[0]); + + let mut output: Vec> = Vec::new(); + + let resolution = evaluate_int(args[8]).max(4) as usize; + let depth = evaluate_int(args[6]); + + let mut max_depth = 0; + for path_data in paths.iter() { + if path_data[2] != 0 { + continue; + } + max_depth = max_depth.max(path_data[3]); + } + + for path_data in paths.iter() { + // if this is not a path don't modify it + if path_data[2] != 0 || path_data[3] < (max_depth - depth) { + output.push(path_data.to_vec()); + continue; + } + + let path = wrap_path(path_data); + + let branch_amount = evaluate_int(args[7]).max(1); + + let lowest_branch = evaluate_float(args[4]); + let highest_branch = evaluate_float(args[5]); + + for i in 0..branch_amount { + let a = i as f32 / (branch_amount - 1).max(1) as f32; + + let length = evaluate_float(args[1]); + let thickness = evaluate_float(args[2]); + let offset_single = evaluate_float(args[3]); + + // log!("a: {}, length: {}, thickness: {}, offset_single: {}, lowest_branch: {}, highest_branch: {}", a, length, thickness, offset_single, lowest_branch, highest_branch); + + // log!("a: {}, length: {}, thickness: {}, offset_single: {}, lowest_branch: {}, highest_branch: {}", a, length, thickness, offset_single, lowest_branch, highest_branch); + let root_alpha = (a * (highest_branch - lowest_branch) + lowest_branch) + .min(1.0) + .max(0.0); + + let is_left = i % 2 == 0; + + let branch_origin = get_point_at_path(path.points, root_alpha); + //const [_vx, , _vz] = interpolateSkeletonVec(stem.skeleton, a); + let direction_slice = get_direction_at_path(path.points, root_alpha); + let direction = Vec3::from_slice(&direction_slice).normalize(); + + let rotation_angle = if is_left { PI } else { -PI }; + + // check if diration contains NaN + if direction[0].is_nan() || direction[1].is_nan() || direction[2].is_nan() { + log!( + "BRANCH direction contains NaN: {:?}, slice: {:?} branch_origin: {:?}, branch: {}", + direction, + direction_slice, + branch_origin, + i + ); + continue; + } + + let branch_direction = Vec3::from_slice(&[ + direction[0] * rotation_angle.cos() - direction[2] * rotation_angle.sin(), + 0.0, + direction[0] * rotation_angle.sin() + direction[2] * rotation_angle.cos(), + ]) + .normalize(); + + log!( + "BRANCH depth: {}, branch_origin: {:?}, direction_at: {:?}, branch_direction: {:?}", + depth, + branch_origin, + direction, + branch_direction + ); + let mut branch_data = create_path(resolution, depth + 1); + let branch = wrap_path_mut(&mut branch_data); + + for j in 0..resolution { + let _a = j as f32 / (resolution - 1) as f32; + branch.points[j * 4] = branch_origin[0] + branch_direction[0] * _a * length; + branch.points[j * 4 + 1] = branch_origin[1] + branch_direction[1] * _a * length; + branch.points[j * 4 + 2] = branch_origin[2] + branch_direction[2] * _a * length; + branch.points[j * 4 + 3] = branch_origin[3] * thickness * (1.0 - _a); + } + + output.push(branch_data); + } + + output.push(path_data.to_vec()); + } + + concat_arg_vecs(output) +} diff --git a/nodes/max/plantarium/array/tests/web.rs b/nodes/max/plantarium/branch/tests/web.rs similarity index 100% rename from nodes/max/plantarium/array/tests/web.rs rename to nodes/max/plantarium/branch/tests/web.rs diff --git a/nodes/max/plantarium/branches/.gitignore b/nodes/max/plantarium/branches/.gitignore deleted file mode 100644 index 4e30131..0000000 --- a/nodes/max/plantarium/branches/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/target -**/*.rs.bk -Cargo.lock -bin/ -pkg/ -wasm-pack.log diff --git a/nodes/max/plantarium/branches/Cargo.toml b/nodes/max/plantarium/branches/Cargo.toml deleted file mode 100644 index 9185f6a..0000000 --- a/nodes/max/plantarium/branches/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "template" -version = "0.1.0" -authors = ["Max Richter "] -edition = "2018" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = ["console_error_panic_hook"] - -[dependencies] -wasm-bindgen = "0.2.84" - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -utils = { version = "0.1.0", path = "../../../../packages/utils" } -macros = { version = "0.1.0", path = "../../../../packages/macros" } -serde = { version = "1.0", features = ["derive"] } -serde-wasm-bindgen = "0.4" -console_error_panic_hook = { version = "0.1.7", optional = true } -web-sys = { version = "0.3.69", features = ["console"] } - -[dev-dependencies] -wasm-bindgen-test = "0.3.34" diff --git a/nodes/max/plantarium/branches/package.json b/nodes/max/plantarium/branches/package.json deleted file mode 100644 index 86916c9..0000000 --- a/nodes/max/plantarium/branches/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "scripts": { - "build": "wasm-pack build --release --out-name index --no-default-features", - "dev": "cargo watch -s 'wasm-pack build --dev --out-name index --no-default-features'" - } -} diff --git a/nodes/max/plantarium/branches/src/lib.rs b/nodes/max/plantarium/branches/src/lib.rs deleted file mode 100644 index b2ac6b5..0000000 --- a/nodes/max/plantarium/branches/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -use macros::include_definition_file; -use utils::{concat_args, decode_float, encode_float, get_args, set_panic_hook, wrap_arg}; -use wasm_bindgen::prelude::*; - -include_definition_file!("src/input.json"); - -#[rustfmt::skip] -#[wasm_bindgen] -pub fn execute(input: &[i32]) -> Vec { - - set_panic_hook(); - - let args = get_args(input); - - let paths = get_args(args[0]); - - concat_args(paths) -} diff --git a/nodes/max/plantarium/branches/tests/web.rs b/nodes/max/plantarium/branches/tests/web.rs deleted file mode 100644 index de5c1da..0000000 --- a/nodes/max/plantarium/branches/tests/web.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Test suite for the Web and headless browsers. - -#![cfg(target_arch = "wasm32")] - -extern crate wasm_bindgen_test; -use wasm_bindgen_test::*; - -wasm_bindgen_test_configure!(run_in_browser); - -#[wasm_bindgen_test] -fn pass() { - assert_eq!(1 + 1, 2); -} diff --git a/nodes/max/plantarium/math/src/lib.rs b/nodes/max/plantarium/math/src/lib.rs index 8b6c7bf..64cd584 100644 --- a/nodes/max/plantarium/math/src/lib.rs +++ b/nodes/max/plantarium/math/src/lib.rs @@ -1,5 +1,5 @@ use macros::include_definition_file; -use utils::{concat_args, get_args, set_panic_hook}; +use utils::{concat_args, set_panic_hook, split_args}; use wasm_bindgen::prelude::*; include_definition_file!("src/input.json"); @@ -7,6 +7,6 @@ include_definition_file!("src/input.json"); #[wasm_bindgen] pub fn execute(args: &[i32]) -> Vec { set_panic_hook(); - let args = get_args(args); + let args = split_args(args); concat_args(vec![&[0], args[0], args[1], args[2]]) } diff --git a/nodes/max/plantarium/noise/src/input.json b/nodes/max/plantarium/noise/src/input.json index 31e1e41..66e740e 100644 --- a/nodes/max/plantarium/noise/src/input.json +++ b/nodes/max/plantarium/noise/src/input.json @@ -36,6 +36,13 @@ 1, 1 ] + }, + "depth": { + "type": "integer", + "min": 1, + "max": 10, + "value": 1, + "hidden": true } } } diff --git a/nodes/max/plantarium/noise/src/lib.rs b/nodes/max/plantarium/noise/src/lib.rs index c83fd22..a1f4933 100644 --- a/nodes/max/plantarium/noise/src/lib.rs +++ b/nodes/max/plantarium/noise/src/lib.rs @@ -2,8 +2,8 @@ use glam::Vec3; use macros::include_definition_file; use noise::{core::open_simplex::open_simplex_2d, permutationtable::PermutationTable, Vector2}; use utils::{ - concat_args, evaluate_float, evaluate_vec3, geometry::wrap_path, get_args, reset_call_count, - set_panic_hook, + concat_args, evaluate_float, evaluate_int, evaluate_vec3, geometry::wrap_path_mut, + reset_call_count, set_panic_hook, split_args, }; use wasm_bindgen::prelude::*; @@ -19,9 +19,9 @@ pub fn execute(input: &[i32]) -> Vec { reset_call_count(); - let args = get_args(input); + let args = split_args(input); - let plants = get_args(args[0]); + let plants = split_args(args[0]); let scale = (evaluate_float(args[1]) * 0.1) as f64; let strength = evaluate_float(args[2]); let fix_bottom = evaluate_float(args[3]); @@ -30,8 +30,18 @@ pub fn execute(input: &[i32]) -> Vec { let directional_strength = evaluate_vec3(args[5]); + let depth = evaluate_int(args[6]); + let hasher = PermutationTable::new(seed as u32); + let mut max_depth = 0; + for path_data in plants.iter() { + if path_data[2] != 0 { + continue; + } + max_depth = max_depth.max(path_data[3]); + } + let output: Vec> = plants .iter() .enumerate() @@ -43,7 +53,11 @@ pub fn execute(input: &[i32]) -> Vec { return path_data; } - let path = wrap_path(&mut path_data); + if path_data[3] < (max_depth - depth + 1) { + return path_data; + } + + let path = wrap_path_mut(&mut path_data); let p0 = Vec3::new(path.points[0], path.points[1], path.points[2]); diff --git a/nodes/max/plantarium/output/src/lib.rs b/nodes/max/plantarium/output/src/lib.rs index 4f4ccd3..6b674a4 100644 --- a/nodes/max/plantarium/output/src/lib.rs +++ b/nodes/max/plantarium/output/src/lib.rs @@ -2,7 +2,7 @@ use macros::include_definition_file; use utils::{ concat_args, evaluate_int, geometry::{extrude_path, wrap_path}, - get_args, log, + log, split_args, }; use wasm_bindgen::prelude::*; @@ -12,9 +12,11 @@ include_definition_file!("src/inputs.json"); pub fn execute(input: &[i32]) -> Vec { utils::set_panic_hook(); - let args = get_args(input); + let args = split_args(input); - let inputs = get_args(args[0]); + assert_eq!(args.len(), 2, "Expected 2 arguments, got {}", args.len()); + + let inputs = split_args(args[0]); let resolution = evaluate_int(args[1]) as usize; @@ -28,10 +30,9 @@ pub fn execute(input: &[i32]) -> Vec { if arg_type == 0 { // this is path - let mut vec = arg.to_vec(); + let vec = arg.to_vec(); output.push(vec.clone()); - let path_data = wrap_path(&mut vec); - log!("{:?}", path_data); + let path_data = wrap_path(arg); let geometry = extrude_path(path_data, resolution); output.push(geometry); } else if arg_type == 1 { diff --git a/nodes/max/plantarium/random/src/lib.rs b/nodes/max/plantarium/random/src/lib.rs index 3eef909..de8c164 100644 --- a/nodes/max/plantarium/random/src/lib.rs +++ b/nodes/max/plantarium/random/src/lib.rs @@ -1,5 +1,5 @@ use macros::include_definition_file; -use utils::{concat_args, get_args, set_panic_hook}; +use utils::{concat_args, set_panic_hook, split_args}; use wasm_bindgen::prelude::*; include_definition_file!("src/definition.json"); @@ -7,6 +7,6 @@ include_definition_file!("src/definition.json"); #[wasm_bindgen] pub fn execute(args: &[i32]) -> Vec { set_panic_hook(); - let args = get_args(args); + let args = split_args(args); concat_args(vec![&[1], args[0], args[1], args[2]]) } diff --git a/nodes/max/plantarium/stem/src/lib.rs b/nodes/max/plantarium/stem/src/lib.rs index 7485671..c9a90a9 100644 --- a/nodes/max/plantarium/stem/src/lib.rs +++ b/nodes/max/plantarium/stem/src/lib.rs @@ -2,7 +2,7 @@ use macros::include_definition_file; use utils::{ evaluate_float, evaluate_int, evaluate_vec3, geometry::{create_multiple_paths, wrap_multiple_paths}, - get_args, log, reset_call_count, set_panic_hook, + log, reset_call_count, set_panic_hook, split_args, }; use wasm_bindgen::prelude::*; @@ -14,7 +14,7 @@ pub fn execute(input: &[i32]) -> Vec { reset_call_count(); - let args = get_args(input); + let args = split_args(input); let amount = evaluate_int(args[1]) as usize; let path_resolution = evaluate_int(args[4]) as usize; diff --git a/nodes/max/plantarium/sum/.gitignore b/nodes/max/plantarium/sum/.gitignore deleted file mode 100644 index 4e30131..0000000 --- a/nodes/max/plantarium/sum/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/target -**/*.rs.bk -Cargo.lock -bin/ -pkg/ -wasm-pack.log diff --git a/nodes/max/plantarium/sum/Cargo.toml b/nodes/max/plantarium/sum/Cargo.toml deleted file mode 100644 index d344d8f..0000000 --- a/nodes/max/plantarium/sum/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "max-plantarium-sum" -version = "0.1.0" -authors = ["Max Richter "] -edition = "2018" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = ["console_error_panic_hook"] - -[dependencies] -wasm-bindgen = "0.2.84" - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -utils = { version = "0.1.0", path = "../../../../packages/utils" } -serde = { version = "1.0", features = ["derive"] } -serde-wasm-bindgen = "0.4" -console_error_panic_hook = { version = "0.1.7", optional = true } -macros = { version = "0.1.0", path = "../../../../packages/macros" } -web-sys = { version = "0.3.69", features = ["console"] } - -[dev-dependencies] -wasm-bindgen-test = "0.3.34" diff --git a/nodes/max/plantarium/sum/package.json b/nodes/max/plantarium/sum/package.json deleted file mode 100644 index 86916c9..0000000 --- a/nodes/max/plantarium/sum/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "scripts": { - "build": "wasm-pack build --release --out-name index --no-default-features", - "dev": "cargo watch -s 'wasm-pack build --dev --out-name index --no-default-features'" - } -} diff --git a/nodes/max/plantarium/sum/src/input.json b/nodes/max/plantarium/sum/src/input.json deleted file mode 100644 index c7d9367..0000000 --- a/nodes/max/plantarium/sum/src/input.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "max/plantarium/sum", - "outputs": [ - "float" - ], - "inputs": { - "array": { - "type": "float", - "value": 2, - "external": true - } - } -} diff --git a/nodes/max/plantarium/sum/src/lib.rs b/nodes/max/plantarium/sum/src/lib.rs deleted file mode 100644 index 4cb3b79..0000000 --- a/nodes/max/plantarium/sum/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -use macros::include_definition_file; -use utils::{decode_float, encode_float}; -use wasm_bindgen::prelude::*; - -include_definition_file!("src/input.json"); - -#[wasm_bindgen] -pub fn execute(input: &[i32]) -> Vec { - utils::set_panic_hook(); - - let mut sum = 0.0; - - // console::log_1(&format!("WASM(sum_node): args: {:?}", input).into()); - - let length = (input.len() - 2) / 2; - - (0..length).for_each(|i| { - // console::log_1(&format!("WASM(sum_node): i: {} sum: {:?}", i, sum).into()); - sum += decode_float(input[2 + i * 2]); - }); - - let encoded_sum = encode_float(sum); - - // console::log_1(&format!("WASM(sum_node): result: {:?}", sum).into()); - - vec![0, 2, encoded_sum] -} diff --git a/nodes/max/plantarium/sum/tests/web.rs b/nodes/max/plantarium/sum/tests/web.rs deleted file mode 100644 index de5c1da..0000000 --- a/nodes/max/plantarium/sum/tests/web.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Test suite for the Web and headless browsers. - -#![cfg(target_arch = "wasm32")] - -extern crate wasm_bindgen_test; -use wasm_bindgen_test::*; - -wasm_bindgen_test_configure!(run_in_browser); - -#[wasm_bindgen_test] -fn pass() { - assert_eq!(1 + 1, 2); -} diff --git a/nodes/max/plantarium/triangle/src/lib.rs b/nodes/max/plantarium/triangle/src/lib.rs index 860771d..10040fe 100644 --- a/nodes/max/plantarium/triangle/src/lib.rs +++ b/nodes/max/plantarium/triangle/src/lib.rs @@ -1,5 +1,5 @@ use macros::include_definition_file; -use utils::{decode_float, encode_float, evaluate_int, get_args, wrap_arg}; +use utils::{decode_float, encode_float, evaluate_int, split_args, wrap_arg}; use wasm_bindgen::prelude::*; use web_sys::console; @@ -11,7 +11,7 @@ pub fn execute(input: &[i32]) -> Vec { utils::set_panic_hook(); - let args = get_args(input); + let args = split_args(input); let size = evaluate_int(args[0]); let decoded = decode_float(size); diff --git a/nodes/max/plantarium/vec3/src/lib.rs b/nodes/max/plantarium/vec3/src/lib.rs index 9531d5a..272156c 100644 --- a/nodes/max/plantarium/vec3/src/lib.rs +++ b/nodes/max/plantarium/vec3/src/lib.rs @@ -1,12 +1,12 @@ use macros::include_definition_file; -use utils::{concat_args, get_args, log}; +use utils::{concat_args, log, split_args}; use wasm_bindgen::prelude::*; include_definition_file!("src/input.json"); #[wasm_bindgen] pub fn execute(input: &[i32]) -> Vec { - let args = get_args(input); + let args = split_args(input); log!("vec3 input: {:?}", input); log!("vec3 args: {:?}", args); concat_args(args) diff --git a/packages/utils/src/geometry/geometry_data.rs b/packages/utils/src/geometry/geometry_data.rs index b2a8cfd..3e0f4d5 100644 --- a/packages/utils/src/geometry/geometry_data.rs +++ b/packages/utils/src/geometry/geometry_data.rs @@ -1,16 +1,16 @@ use crate::log; +static GEOMETRY_HEADER_SIZE: usize = 3; +// 0: geometry type = 0 +// 1: vertex amount +// 2: face amount + pub struct GeometryData<'a> { pub positions: &'a mut [f32], // View into `data` pub normals: &'a mut [f32], // View into `data` pub faces: &'a mut [i32], // View into `data` } -static GEOMETRY_HEADER_SIZE: usize = 3; -// 0: geometry type = 0 -// 1: vertex amount -// 2: face amount - pub fn create_geometry_data(vertex_amount: usize, face_amount: usize) -> Vec { let amount = GEOMETRY_HEADER_SIZE // definition (type, vertex_amount, face_amount) + 4 // opening and closing brackets diff --git a/packages/utils/src/geometry/path_data.rs b/packages/utils/src/geometry/path_data.rs index 5b6df35..c13e085 100644 --- a/packages/utils/src/geometry/path_data.rs +++ b/packages/utils/src/geometry/path_data.rs @@ -1,14 +1,20 @@ -static PATH_HEADER_SIZE: usize = 2; // 0: node-type, stem: 0 // 1: depth +static PATH_HEADER_SIZE: usize = 2; #[derive(Debug)] -pub struct PathData<'a> { - pub header: &'a mut [i32], +pub struct PathDataMut<'a> { pub length: usize, + pub depth: i32, pub points: &'a mut [f32], } +pub struct PathData<'a> { + pub depth: i32, + pub length: usize, + pub points: &'a [f32], +} + pub fn create_multiple_paths(amount: usize, point_amount: usize, depth: i32) -> Vec { let output_size = amount * (point_amount * 4 + PATH_HEADER_SIZE + 4) + 4; @@ -35,7 +41,7 @@ pub fn create_multiple_paths(amount: usize, point_amount: usize, depth: i32) -> path } -pub fn wrap_multiple_paths(mut input: &mut [i32]) -> Vec> { +pub fn wrap_multiple_paths(mut input: &mut [i32]) -> Vec> { let mut paths = Vec::new(); let mut end_index = 2; @@ -46,7 +52,7 @@ pub fn wrap_multiple_paths(mut input: &mut [i32]) -> Vec> { end_index = input[1] as usize + 3; if end_index < input.len() { let (path_slice, remaining) = input.split_at_mut(end_index); - let path_data = wrap_path(path_slice); + let path_data = wrap_path_mut(path_slice); paths.push(path_data); input = remaining; } else { @@ -63,7 +69,7 @@ pub fn create_path(point_amount: usize, depth: i32) -> Vec { let mut path: Vec = vec![0; output_size]; path[0] = 0; // encode opening bracket - path[1] = (point_amount * 4) as i32 + 2; // encode opening bracket + path[1] = ((point_amount * 4) + PATH_HEADER_SIZE + 1) as i32; // encode opening bracket path[2] = 0; //encode node-type, stem: 0 path[3] = depth; //encode depth path[output_size - 2] = 1; // encode closing bracket @@ -72,7 +78,39 @@ pub fn create_path(point_amount: usize, depth: i32) -> Vec { path } -pub fn wrap_path<'a>(geometry: &'a mut [i32]) -> PathData<'a> { +pub fn wrap_path(input: &[i32]) -> PathData { + // Basic validity checks + assert!( + input.len() > PATH_HEADER_SIZE, + "Geometry vector does not contain enough data for a header." + ); + + let rest = &input[2..]; + + let header = &rest[..PATH_HEADER_SIZE]; + + let points_slice = &rest[PATH_HEADER_SIZE..rest.len() - 2]; + + assert!( + points_slice.len() % 4 == 0, + "Points slice does not match the expected size. {}", + points_slice.len() + ); + + let length = points_slice.len() / 4; + + let points: &[f32] = unsafe { + std::slice::from_raw_parts(points_slice.as_ptr() as *const f32, points_slice.len()) + }; + + PathData { + depth: header[1], + length, + points, + } +} + +pub fn wrap_path_mut<'a>(geometry: &'a mut [i32]) -> PathDataMut<'a> { // Basic validity checks assert!( geometry.len() > PATH_HEADER_SIZE, @@ -89,7 +127,8 @@ pub fn wrap_path<'a>(geometry: &'a mut [i32]) -> PathData<'a> { assert!( points_slice.len() % 4 == 0, - "Points slice does not match the expected size.", + "Points slice does not match the expected size. {}", + points_slice.len() ); let length = points_slice.len() / 4; @@ -98,9 +137,73 @@ pub fn wrap_path<'a>(geometry: &'a mut [i32]) -> PathData<'a> { std::slice::from_raw_parts_mut(points_slice.as_mut_ptr() as *mut f32, points_slice.len()) }; - PathData { - header, + PathDataMut { + depth: header[1], length, points, } } + +pub fn get_point_at_path(path: &[f32], alpha: f32) -> [f32; 4] { + let a = alpha.min(0.999999).max(0.000001); + + let num_points = path.len() / 4; + let segment_length = 1.0 / (num_points - 1) as f32; + let mut target_index = (a / segment_length).floor() as usize; + target_index = target_index.min(num_points - 2); // Ensure it doesn't exceed bounds + + let start_index = target_index * 4; + let end_index = (target_index + 1) * 4; + + let t = (a - target_index as f32 * segment_length) / segment_length; + + let x1 = path[start_index]; + let y1 = path[start_index + 1]; + let z1 = path[start_index + 2]; + let w1 = path[start_index + 3]; + + let x2 = path[end_index]; + let y2 = path[end_index + 1]; + let z2 = path[end_index + 2]; + let w2 = path[end_index + 3]; + + // Linear interpolation + let x = x1 + t * (x2 - x1); + let y = y1 + t * (y2 - y1); + let z = z1 + t * (z2 - z1); + let w = w1 + t * (w2 - w1); + + [x, y, z, w] +} + +pub fn get_direction_at_path(path: &[f32], alpha: f32) -> [f32; 3] { + let num_points = path.len() / 4; + + let a = alpha.min(0.999999).max(0.000001); + + let segment_length = 1.0 / (num_points - 1) as f32; + let target_index = (a / segment_length).floor() as usize; + + let start_index = target_index * 4; + let end_index = (target_index + 1) * 4; + + let x1 = path[start_index]; + let y1 = path[start_index + 1]; + let z1 = path[start_index + 2]; + let x2 = path[end_index]; + let y2 = path[end_index + 1]; + let z2 = path[end_index + 2]; + + // Direction vector (not normalized) + let dx = x2 - x1; + let dy = y2 - y1; + let dz = z2 - z1; + + let norm = (dx * dx + dy * dy + dz * dz).sqrt(); + + if norm == 0.0 { + return [0.0, 1.0, 0.0]; + } + + [dx / norm, dy / norm, dz / norm] +} diff --git a/packages/utils/src/tree.rs b/packages/utils/src/tree.rs index 89e27dc..ef7854d 100644 --- a/packages/utils/src/tree.rs +++ b/packages/utils/src/tree.rs @@ -1,6 +1,6 @@ use crate::decode_float; -pub fn get_args(args: &[i32]) -> Vec<&[i32]> { +pub fn split_args(args: &[i32]) -> Vec<&[i32]> { println!("-------------------"); println!("{:?}", args); @@ -47,14 +47,12 @@ pub fn get_args(args: &[i32]) -> Vec<&[i32]> { } i += 2; continue; + } else if depth == 1 { + out_args.push(&args[i..i + 1]); + println!("-> {:?}", &args[i..i + 1]); + start_index = i + 1; } else { - if depth == 1 { - out_args.push(&args[i..i + 1]); - println!("-> {:?}", &args[i..i + 1]); - start_index = i + 1; - } else { - println!("{}", val); - } + println!("{}", val); } i += 1; @@ -63,6 +61,46 @@ pub fn get_args(args: &[i32]) -> Vec<&[i32]> { out_args } +pub fn concat_arg_vecs(data: Vec>) -> Vec { + let mut total_length = 4; // Start with 4 to account for [0, 1] at the start and [1, 1] at the end + + // Calculate the total length first to avoid reallocations + for vec in &data { + if vec.len() == 1 { + total_length += 1; + } else { + total_length += vec.len(); // +4 for [0, 1] and [1, 1] per inner vec + } + } + + let mut result = Vec::with_capacity(total_length); + + // Add [0, 1] initially + result.push(0); + result.push(1); + + let mut last_closing_bracket = 1; + + // Process each vector + for vec in data { + if vec.len() == 1 { + result.push(vec[0]); + result[last_closing_bracket] += 1; + continue; + } else { + result.extend(vec); + last_closing_bracket = result.len() - 1; + result[last_closing_bracket] = 1; + } + } + + // Add [1, 1] at the end + result.push(1); + result.push(1); + + result +} + pub fn concat_args(mut data: Vec<&[i32]>) -> Vec { let mut total_length = 4; // Start with 4 to account for [0, 1] at the start and [1, 1] at the end @@ -131,7 +169,7 @@ pub fn evaluate_vec3(input_args: &[i32]) -> Vec { ]; } - let args = get_args(input_args); + let args = split_args(input_args); assert!( args.len() == 3, @@ -156,7 +194,7 @@ pub fn evaluate_int(input_args: &[i32]) -> i32 { return input_args[0]; } - let args = get_args(input_args); + let args = split_args(input_args); let mut resolved: Vec = Vec::new(); @@ -192,7 +230,7 @@ mod tests { 1053609165, 54, ]; - let args = get_args(&input); + let args = split_args(&input); println!("{:?}", args[0]); assert_eq!(args[0].len(), 29); @@ -219,7 +257,7 @@ mod tests { let input_a = vec![0, 4, 1, 2, 3, 0, 7, 1, 2, 4, 2, 4, 1, 1, 1, 1]; // -> [1, 2, 3, [1, 2, 4, 2, 4]] - let args = get_args(&input_a); + let args = split_args(&input_a); println!("{:?}", args); @@ -235,7 +273,7 @@ mod tests { let input_b = vec![0, 3, 7, 1, 0, 4, 4, 2, 4, 1, 2, 2, 0, 3, 2, 3, 1, 1, 1, 1]; // -> [1,[4,2,4], 2, [2,3]] - let args = get_args(&input_b); + let args = split_args(&input_b); assert_eq!(args.len(), 5); assert_eq!(args[0], [7]); @@ -258,14 +296,14 @@ mod tests { // 2 -> first number // 3 -> second number - let args = get_args(&input); + let args = split_args(&input); assert_eq!(args.len(), 4); assert_eq!(args[0], [0]); assert_eq!(args[1], [2]); assert_eq!(args[3], [0, 3, 0, 128]); - let nested_args = get_args(args[2]); + let nested_args = split_args(args[2]); assert_eq!(nested_args.len(), 4); }