diff --git a/Cargo.lock b/Cargo.lock index b533c80..72c45bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -374,6 +374,7 @@ dependencies = [ "serde", "serde_json", "wasm-bindgen", + "web-sys", ] [[package]] diff --git a/app/src/lib/runtime-executor.ts b/app/src/lib/runtime-executor.ts index 5753a94..4c4ed0d 100644 --- a/app/src/lib/runtime-executor.ts +++ b/app/src/lib/runtime-executor.ts @@ -1,9 +1,5 @@ import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "@nodes/types"; -import { encodeFloat } from "./helpers/encode"; -import { concat_encoded } from "./helpers/flat_tree"; -import { fastHash } from "./helpers/fastHash"; - - +import { fastHash, concat_encoded, encodeFloat } from "@nodes/utils" export class MemoryRuntimeExecutor implements RuntimeExecutor { diff --git a/app/src/lib/viewer/Scene.svelte b/app/src/lib/viewer/Scene.svelte index bce3062..2e81e0d 100644 --- a/app/src/lib/viewer/Scene.svelte +++ b/app/src/lib/viewer/Scene.svelte @@ -16,29 +16,29 @@ } + + + {#each geometry as geo} - {#each geo.attributes.position.array as attr, i} - {#if i % 3 === 0} - - {/if} - {/each} + {#if false} + {#each geo.attributes.position.array as _, i} + {#if i % 3 === 0} + + {/if} + {/each} - - - - + + + + + {/if} - - -{:else} - - - + {/each} diff --git a/app/src/lib/viewer/Viewer.svelte b/app/src/lib/viewer/Viewer.svelte index c829f8a..5eddfdc 100644 --- a/app/src/lib/viewer/Viewer.svelte +++ b/app/src/lib/viewer/Viewer.svelte @@ -38,12 +38,13 @@ ); index = index + vertexCount * 3; + console.log({ vertices, normals, indices }); + // Add data to geometry geometry.setIndex([...indices]); geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3)); geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3)); - // geometry.computeVertexNormals(); - //geometry.computeVertexNormals(); + geometry.computeVertexNormals(); return geometry; } @@ -94,19 +95,19 @@ $: if (result) { const inputs = parse_args(result); - for (let input of inputs) { - if (input[0] === 1) { - const geo = createGeometryFromEncodedData(input); - geometries = [geo]; - console.log(geo); - } - } + console.log({ inputs }); + + geometries = inputs + .map((input) => { + if (input[0] === 1) { + const geo = createGeometryFromEncodedData(input); + return geo; + } + }) + .filter(Boolean) as BufferGeometry[]; } - - diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index fbf69f4..fb8d1d6 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -5,8 +5,7 @@ import { RemoteNodeRegistry } from "$lib/node-registry"; import * as templates from "$lib/graph-templates"; import type { Graph } from "@nodes/types"; - import { decode, encode } from "$lib/helpers/flat_tree"; - import { decodeFloat, encodeFloat } from "$lib/helpers/encode"; + import { decode, encode, decodeFloat, encodeFloat } from "@nodes/utils"; import Viewer from "$lib/viewer/Viewer.svelte"; globalThis.decode = decode; @@ -14,6 +13,41 @@ globalThis.df = decodeFloat; globalThis.en = encodeFloat; + globalThis.ci = function createIndeces(resX: number, stemLength = 1) { + const index = new Uint16Array(resX * (Math.max(stemLength, 1) - 1) * 6); + + for (let i = 0; i < stemLength; i++) { + const indexOffset = i * resX * 6; + const positionOffset = i * resX; + for (let j = 0; j < resX; j++) { + const _indexOffset = indexOffset + j * 6; + const _positionOffset = positionOffset + j; + + console.log(`iio: ${_indexOffset} pio: ${_positionOffset} j: ${j}`); + + if (j === resX - 1) { + index[_indexOffset + 0] = _positionOffset + 1; + index[_indexOffset + 1] = _positionOffset - resX + 1; + index[_indexOffset + 2] = _positionOffset; + + index[_indexOffset + 3] = _positionOffset; + index[_indexOffset + 4] = _positionOffset + resX; + index[_indexOffset + 5] = _positionOffset + 1; + } else { + index[_indexOffset + 0] = _positionOffset + resX + 1; + index[_indexOffset + 1] = _positionOffset + 1; + index[_indexOffset + 2] = _positionOffset; + + index[_indexOffset + 3] = _positionOffset; + index[_indexOffset + 4] = _positionOffset + resX; + index[_indexOffset + 5] = _positionOffset + resX + 1; + } + } + } + + return index; + }; + const nodeRegistry = new RemoteNodeRegistry("http://localhost:3001"); const runtimeExecutor = new MemoryRuntimeExecutor(nodeRegistry); @@ -28,7 +62,7 @@ let a = performance.now(); res = runtimeExecutor.execute(event.detail); time = performance.now() - a; - console.log(res); + console.log({ res, time }); } function handleSave(event: CustomEvent) { diff --git a/nodes/max/plantarium/box/src/lib.rs b/nodes/max/plantarium/box/src/lib.rs index 7578314..443d37c 100644 --- a/nodes/max/plantarium/box/src/lib.rs +++ b/nodes/max/plantarium/box/src/lib.rs @@ -1,4 +1,4 @@ -use crate::geometry::calculate_normals::calculate_normals; +use crate::geometry::calculate_normals; use macros::include_definition_file; use utils::{ decode_float, encode_float, evaluate_args, geometry, get_args, set_panic_hook, wrap_arg, diff --git a/nodes/max/plantarium/output/src/lib.rs b/nodes/max/plantarium/output/src/lib.rs index 83b67af..87c1ff8 100644 --- a/nodes/max/plantarium/output/src/lib.rs +++ b/nodes/max/plantarium/output/src/lib.rs @@ -1,36 +1,31 @@ use macros::include_definition_file; -use utils::{concat_args, decode_float, encode_float, get_args}; +use utils::{concat_args, geometry::extrude_path, get_args}; use wasm_bindgen::prelude::*; -use web_sys::console; include_definition_file!("src/inputs.json"); #[rustfmt::skip] #[wasm_bindgen] -pub fn execute(input: &[i32]) -> Vec { +pub fn execute(input: Vec) -> Vec { utils::set_panic_hook(); - let args = get_args(input); + let args = get_args(input.as_slice()); - console::log_1(&format!("WASM(output_node): input: {:?}", args).into()); - - let mut output:Vec<&[i32]> = Vec::new(); + let mut output:Vec> = Vec::new(); for arg in args { - if arg.len() < 3 { - continue; + if arg.len() < 3 { continue; } + + if arg[2] == 0 { + let _arg = &arg[3..]; + let geometry = extrude_path(_arg, 8); + output.push(geometry); + }else if arg[2] == 1 { + output.push(arg.to_vec()); } - output.push( match arg[2] { - // stem - 0 => &[0,1,1,1], - // geometry - 1 => arg, - _ => &[0,1,1,1], - }) } concat_args(output) - } diff --git a/nodes/max/plantarium/stem/src/lib.rs b/nodes/max/plantarium/stem/src/lib.rs index 001ccf8..f40dde2 100644 --- a/nodes/max/plantarium/stem/src/lib.rs +++ b/nodes/max/plantarium/stem/src/lib.rs @@ -1,42 +1,42 @@ use macros::include_definition_file; -use utils::{evaluate_args, get_args}; +use utils::{decode_float, evaluate_args, get_args, log, set_panic_hook, wrap_arg}; use wasm_bindgen::prelude::*; -use web_sys::console; include_definition_file!("src/input.json"); #[wasm_bindgen] pub fn execute(input: &[i32]) -> Vec { + set_panic_hook(); + let args = get_args(input); - let length = evaluate_args(args[0]); - let thickness = evaluate_args(args[1]); - let resolution = 32; //evaluate_args(args[2]); + let length = decode_float(evaluate_args(args[0])[0]); + let thickness = decode_float(evaluate_args(args[1])[0]); + let resolution = 64; //evaluate_args(args[2]); - console::log_1( - &format!( - "length: {:?}, thickness: {:?}, resolution: {:?}", - length, thickness, resolution - ) - .into(), - ); + let mut path: Vec = vec![0; resolution * 4 + 1]; + path.resize(resolution * 4 + 1, 0); - vec![ - 0, 1, 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 - 1, // closing bracket - 1, //closing bracket - ] + path[0] = 0; + + let slice = &mut path[1..]; + + // Unsafe code to transmute the i32 slice to an f32 slice + let path_p: &mut [f32] = unsafe { + // Ensure that the length of the slice is a multiple of 4 + assert_eq!(slice.len() % 4, 0); + + // Transmute the i32 slice to an f32 slice + std::slice::from_raw_parts_mut(slice.as_ptr() as *mut f32, slice.len()) + }; + + for i in 0..resolution { + let a = i as f32 / resolution as f32; + path_p[i * 4] = (a * 8.0).sin() * 0.2; + path_p[i * 4 + 1] = a * length; + path_p[i * 4 + 2] = 0.0; + path_p[i * 4 + 3] = thickness * (1.0 - a); + } + + wrap_arg(&path) } diff --git a/nodes/max/plantarium/triangle/src/lib.rs b/nodes/max/plantarium/triangle/src/lib.rs index 0f4a2ff..cdbf1db 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::{concat_args, decode_float, encode_float}; +use utils::{concat_args, decode_float, encode_float, wrap_arg}; use wasm_bindgen::prelude::*; use web_sys::console; @@ -16,8 +16,7 @@ pub fn execute(input: &[i32]) -> Vec { console::log_1(&format!("WASM(triangle): input: {:?} -> {}", input, decoded).into()); // [[1,3, x, y, z, x, y,z,x,y,z]]; - concat_args(vec![&[ - 0, 19, // opening bracket + distance to next bracket + wrap_arg(&[ 1, // 1: geometry 3, // 3 vertices 1, // 1 face @@ -37,8 +36,6 @@ pub fn execute(input: &[i32]) -> Vec { 0, // x -> point 3 0, // y size, // z - // - 1, 1 // closing brackets - ]]) + ]) } diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml index 9d4aa3d..d51cef1 100644 --- a/packages/utils/Cargo.toml +++ b/packages/utils/Cargo.toml @@ -8,6 +8,7 @@ default = ["console_error_panic_hook"] [dependencies] wasm-bindgen = "0.2.92" +web-sys = { version = "0.3.69", features = ["console"] } 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 } diff --git a/app/src/lib/helpers/encode.test.ts b/packages/utils/src/encoding.test.ts similarity index 100% rename from app/src/lib/helpers/encode.test.ts rename to packages/utils/src/encoding.test.ts diff --git a/app/src/lib/helpers/encode.ts b/packages/utils/src/encoding.ts similarity index 100% rename from app/src/lib/helpers/encode.ts rename to packages/utils/src/encoding.ts diff --git a/app/src/lib/helpers/fastHash.test.ts b/packages/utils/src/fastHash.test.ts similarity index 100% rename from app/src/lib/helpers/fastHash.test.ts rename to packages/utils/src/fastHash.test.ts diff --git a/app/src/lib/helpers/fastHash.ts b/packages/utils/src/fastHash.ts similarity index 100% rename from app/src/lib/helpers/fastHash.ts rename to packages/utils/src/fastHash.ts diff --git a/app/src/lib/helpers/flat_tree.test.ts b/packages/utils/src/flatTree.test.ts similarity index 100% rename from app/src/lib/helpers/flat_tree.test.ts rename to packages/utils/src/flatTree.test.ts diff --git a/app/src/lib/helpers/flat_tree.ts b/packages/utils/src/flatTree.ts similarity index 100% rename from app/src/lib/helpers/flat_tree.ts rename to packages/utils/src/flatTree.ts diff --git a/packages/utils/src/geometry/extrude_path.rs b/packages/utils/src/geometry/extrude_path.rs index e8dc5da..fad5ea2 100644 --- a/packages/utils/src/geometry/extrude_path.rs +++ b/packages/utils/src/geometry/extrude_path.rs @@ -1 +1,115 @@ -pub fn extrude_path(path: &[i32]) {} +use crate::log; + +use super::create_empty_geometry; +use glam::{Mat4, Quat, Vec3}; + +fn create_circle(res: usize) -> Vec { + let angle = (2.0 * std::f32::consts::PI) / res as f32; + let mut circle = Vec::new(); + for i in 0..res { + circle.push((angle * i as f32).cos()); + circle.push((angle * i as f32).sin()); + } + circle +} + +#[rustfmt::skip] +pub fn extrude_path(input_path: &[i32], res_x: usize) -> Vec { + let point_amount = input_path.len() / 4; + let face_amount = (point_amount - 1) * res_x * 2; + let vertices_amount = point_amount * res_x; + + let circle = create_circle(res_x); + + let mut geometry = create_empty_geometry(vertices_amount, face_amount); + + let (_header,rest) = geometry.split_at_mut(5); + let (indices, rest) = rest.split_at_mut(face_amount*3); + let (_positions, _normals) = rest.split_at_mut(vertices_amount*3); + let positions: &mut [f32]; + let normals: &mut [f32]; + let path: &[f32]; + unsafe { + path = std::slice::from_raw_parts(input_path.as_ptr() as *const f32, input_path.len()); + positions = std::slice::from_raw_parts_mut(_positions.as_mut_ptr() as *mut f32, _positions.len()); + normals = std::slice::from_raw_parts_mut(_normals.as_mut_ptr() as *mut f32, _normals.len()); + } + + normals[0] = 0.0; + + for i in 0..point_amount { + + let index_offset = i * res_x * 6; + let position_offset = i * res_x; + + let point = Vec3::from_slice(&path[i*4..i*4+3]); + let thickness = path[i*4+3]; + let next_point = if i == point_amount - 1 { point } else { Vec3::from_slice(&path[(i+1)*4..(i+1)*4+3]) }; + let prev_point = if i == 0 { point } else { Vec3::from_slice(&path[(i-1)*4..(i-1)*4+3]) }; + + let mut v = if i == 0 { + point - next_point + } else if i == point_amount - 1 { + prev_point - point + } else { + prev_point - next_point + }; + v = v.normalize(); + + let n = Vec3::new(0.0, 1.0, 0.0); // Assuming 'n' is the up vector or similar + let axis = n.cross(v); + let angle = n.dot(v).acos(); + + let quat = Quat::from_axis_angle(axis, angle); + let mat = Mat4::IDENTITY * Mat4::from_quat(quat); + + for j in 0..res_x { + + if i < point_amount - 1 { + + let i_index_offset = index_offset + j * 6; + let i_position_offset = position_offset + j; + + if j == res_x - 1 { + indices[i_index_offset ] = (i_position_offset + 1) as i32; + indices[i_index_offset + 1] = (i_position_offset - res_x + 1) as i32; + indices[i_index_offset + 2] = (i_position_offset) as i32; + indices[i_index_offset + 3] = (i_position_offset) as i32; + indices[i_index_offset + 4] = (i_position_offset + res_x) as i32; + indices[i_index_offset + 5] = (i_position_offset + 1) as i32; + } else { + indices[i_index_offset ] = (i_position_offset + res_x + 1) as i32; + indices[i_index_offset + 1] = (i_position_offset + 1) as i32; + indices[i_index_offset + 2] = (i_position_offset) as i32; + indices[i_index_offset + 3] = (i_position_offset) as i32; + indices[i_index_offset + 4] = (i_position_offset + res_x) as i32; + indices[i_index_offset + 5] = (i_position_offset + res_x + 1) as i32; + } + } + + // construct the points + let idx = i * res_x * 3 + j * 3; + + let circle_x = circle[j * 2 ] * thickness; + let circle_y = circle[j * 2 + 1] * thickness; + + let _pt = Vec3::new( + point[0] + circle_x, + point[1], + point[2] + circle_y, + ); + + let pt = Mat4::transform_point3(&mat, _pt) + point; + + normals[idx ] = circle_x; + normals[idx + 1] = 0.0; + normals[idx + 2] = circle_y; + + positions[idx ] = pt[0]; + positions[idx + 1] = pt[1]; + positions[idx + 2] = pt[2]; + } + } + + geometry +} diff --git a/packages/utils/src/geometry/mod.rs b/packages/utils/src/geometry/mod.rs index 70d5d25..db9300a 100644 --- a/packages/utils/src/geometry/mod.rs +++ b/packages/utils/src/geometry/mod.rs @@ -1,3 +1,34 @@ -pub mod calculate_normals; -pub mod extrude_path; +mod calculate_normals; +mod extrude_path; +pub use calculate_normals::*; +pub use extrude_path::*; + +use crate::log; + +#[rustfmt::skip] +pub fn create_empty_geometry(vertex_amount: usize, face_amount: usize) -> Vec { + log!( + "create_empty_geometry: vertex_amount: {}, face_amount: {}", + vertex_amount, + face_amount + ); + + let amount = + 3 // definition (type, vertex_amount, face_amount) + + 4 // opening and closing brackets + + vertex_amount * 3 // positions + + vertex_amount * 3 // normals + + face_amount * 3; // faces + + + let mut vec: Vec = vec![0; amount]; + vec[0] = 0; // opening bracket + vec[1] = amount as i32 - 2; // opening bracket + vec[2] = 1; // type: geometry + vec[3] = vertex_amount as i32; + vec[4] = face_amount as i32; + vec[amount - 2] = 1; // closing bracket + vec[amount - 1] = 1; // closing bracket + vec +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 70c54ed..50fb390 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1 +1,4 @@ export * from "./wasm-wrapper"; +export * from "./flatTree" +export * from "./encoding" +export * from "./fastHash" diff --git a/packages/utils/src/lib.rs b/packages/utils/src/lib.rs index ee52fd2..e100a7e 100644 --- a/packages/utils/src/lib.rs +++ b/packages/utils/src/lib.rs @@ -7,6 +7,14 @@ pub use helpers::*; pub use tree::*; pub mod geometry; +#[macro_export] +macro_rules! log { + ($($arg:tt)*) => {{ + use web_sys::console; + console::log_1(&format!($($arg)*).into()); + }} +} + pub fn set_panic_hook() { // When the `console_error_panic_hook` feature is enabled, we can call the // `set_panic_hook` function at least once during initialization, and then diff --git a/packages/utils/src/tree.rs b/packages/utils/src/tree.rs index 60dec74..f602fce 100644 --- a/packages/utils/src/tree.rs +++ b/packages/utils/src/tree.rs @@ -57,20 +57,34 @@ pub fn get_args(args: &[i32]) -> Vec<&[i32]> { out_args } -pub fn concat_args(args: Vec<&[i32]>) -> Vec { - let total_length: usize = args.iter().map(|arg| arg.len()).sum(); +pub fn concat_args(mut 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 - let mut out_args = Vec::with_capacity(total_length + 4); - - out_args.extend_from_slice(&[0, 1]); - - for arg in args { - out_args.extend_from_slice(arg); + // Calculate the total length first to avoid reallocations + for vec in &data { + total_length += vec.len(); // +4 for [0, 1] and [1, 1] per inner vec } - out_args.extend_from_slice(&[1, 1]); + let mut result = Vec::with_capacity(total_length); - out_args + // Add [0, 1] initially + // result.push(0); + // result.push(1); + + // Process each vector + for vec in data.iter_mut() { + result.push(0); + result.push(1); + result.append(vec); + result.push(1); + result.push(1); + } + + // Add [1, 1] at the end + // result.push(1); + // result.push(1); + + result } pub fn wrap_arg(arg: &[i32]) -> Vec {