diff --git a/.dprint.jsonc b/.dprint.jsonc index 7fedc9c..ab96722 100644 --- a/.dprint.jsonc +++ b/.dprint.jsonc @@ -47,13 +47,13 @@ "**/target", ], "plugins": [ - "https://plugins.dprint.dev/typescript-0.95.13.wasm", + "https://plugins.dprint.dev/typescript-0.95.15.wasm", "https://plugins.dprint.dev/json-0.21.1.wasm", - "https://plugins.dprint.dev/markdown-0.20.0.wasm", + "https://plugins.dprint.dev/markdown-0.21.1.wasm", "https://plugins.dprint.dev/toml-0.7.0.wasm", "https://plugins.dprint.dev/dockerfile-0.3.3.wasm", "https://plugins.dprint.dev/g-plane/markup_fmt-v0.25.3.wasm", - "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm", + "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.6.0.wasm", "https://plugins.dprint.dev/exec-0.6.0.json@a054130d458f124f9b5c91484833828950723a5af3f8ff2bd1523bd47b83b364", ], } diff --git a/.gitea/scripts/build.sh b/.gitea/scripts/build.sh index f26717c..01542d4 100755 --- a/.gitea/scripts/build.sh +++ b/.gitea/scripts/build.sh @@ -21,6 +21,8 @@ else COMMITS_SINCE_LAST_RELEASE="0" fi +commit_message=$(git log -1 --pretty=%B | tr -d '\n' | sed 's/"/\\"/g') + cat >app/static/git.json <app/static/git.json < @@ -51,6 +61,9 @@ }, dimensions: { value: [100, 100] + }, + gridType: { + value: 0 } }} uniforms.camPos.value={cameraPosition} @@ -59,6 +72,7 @@ uniforms.lineColor.value={appSettings.value.theme && colors['outline']} uniforms.zoomLimits.value={[minZoom, maxZoom]} uniforms.dimensions.value={[width, height]} + uniforms.gridType.value={gridType} /> diff --git a/app/src/lib/graph-interface/edges/Edge.svelte b/app/src/lib/graph-interface/edges/Edge.svelte index 884e90e..fe58df3 100644 --- a/app/src/lib/graph-interface/edges/Edge.svelte +++ b/app/src/lib/graph-interface/edges/Edge.svelte @@ -2,19 +2,19 @@ import { colors } from '../graph/colors.svelte'; const circleMaterial = new MeshBasicMaterial({ - color: colors.edge.clone(), + color: colors.outline.clone(), toneMapped: false }); - let lineColor = $state(colors.edge.clone().convertSRGBToLinear()); + let lineColor = $state(colors.outline.clone().convertSRGBToLinear()); $effect.root(() => { $effect(() => { if (appSettings.value.theme === undefined) { return; } - circleMaterial.color = colors.edge.clone().convertSRGBToLinear(); - lineColor = colors.edge.clone().convertSRGBToLinear(); + circleMaterial.color = colors.outline.clone().convertSRGBToLinear(); + lineColor = colors.outline.clone().convertSRGBToLinear(); }); }); diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index 4b8a001..512fe39 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -83,7 +83,7 @@ export class GraphState { addMenuPosition = $state<[number, number] | null>(null); snapToGrid = $state(false); - showGrid = $state(true); + backgroundType = $state<'grid' | 'dots' | 'none'>('grid'); showHelp = $state(false); cameraDown = [0, 0]; @@ -186,15 +186,25 @@ export class GraphState { if (!node?.inputs) { return 5; } - const height = 5 - + 10 - * Object.keys(node.inputs).filter( - (p) => - p !== 'seed' - && node?.inputs - && !(node?.inputs?.[p] !== undefined && 'setting' in node.inputs[p]) - && node.inputs[p].hidden !== true - ).length; + let height = 5; + + for (const key of Object.keys(node.inputs)) { + if (key === 'seed') continue; + if (!node.inputs) continue; + if (node?.inputs?.[key] === undefined) continue; + if ('setting' in node.inputs[key]) continue; + if (node.inputs[key].hidden) continue; + if ( + node.inputs[key].type === 'shape' + && node.inputs[key].external !== true + && node.inputs[key].internal !== false + ) { + height += 20; + continue; + } + height += 10; + } + this.nodeHeightCache[nodeTypeId] = height; return height; } diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index bc36434..06fe2c5 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -132,8 +132,9 @@ position={graphState.cameraPosition} /> - {#if graphState.showGrid !== false} + {#if graphState.backgroundType !== 'none'} ; activeNode?: NodeInstance; - showGrid?: boolean; + backgroundType?: 'grid' | 'dots' | 'none'; snapToGrid?: boolean; showHelp?: boolean; settingTypes?: Record; @@ -27,7 +27,7 @@ registry, settings = $bindable(), activeNode = $bindable(), - showGrid = $bindable(true), + backgroundType = $bindable('grid'), snapToGrid = $bindable(true), showHelp = $bindable(false), settingTypes = $bindable(), @@ -43,7 +43,7 @@ const graphState = new GraphState(manager); $effect(() => { - graphState.showGrid = showGrid; + graphState.backgroundType = backgroundType; graphState.snapToGrid = snapToGrid; graphState.showHelp = showHelp; }); diff --git a/app/src/lib/graph-interface/graph/colors.svelte.ts b/app/src/lib/graph-interface/graph/colors.svelte.ts index 6f1f5a9..9f85c6b 100644 --- a/app/src/lib/graph-interface/graph/colors.svelte.ts +++ b/app/src/lib/graph-interface/graph/colors.svelte.ts @@ -9,7 +9,7 @@ const variables = [ 'outline', 'active', 'selected', - 'edge' + 'connection' ] as const; function getColor(variable: (typeof variables)[number]) { diff --git a/app/src/lib/graph-interface/graph/mouse.events.ts b/app/src/lib/graph-interface/graph/mouse.events.ts index ad553a3..e7c32c0 100644 --- a/app/src/lib/graph-interface/graph/mouse.events.ts +++ b/app/src/lib/graph-interface/graph/mouse.events.ts @@ -166,15 +166,14 @@ export class MouseEventManager { if (this.state.mouseDown) return; this.state.edgeEndPosition = null; + const target = event.target as HTMLElement; - if (event.target instanceof HTMLElement) { - if ( - event.target.nodeName !== 'CANVAS' - && !event.target.classList.contains('node') - && !event.target.classList.contains('content') - ) { - return; - } + if ( + target.nodeName !== 'CANVAS' + && !target.classList.contains('node') + && !target.classList.contains('content') + ) { + return; } const mx = event.clientX - this.state.rect.x; diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index 5fdf383..0e72475 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -57,7 +57,7 @@ uniforms={{ uColorBright: { value: colors['layer-2'] }, uColorDark: { value: colors['layer-1'] }, - uStrokeColor: { value: colors.outline.clone() }, + uStrokeColor: { value: colors['layer-2'].clone() }, uStrokeWidth: { value: 1.0 }, uWidth: { value: 20 }, uHeight: { value: height } diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte index a773ba0..a3bdb11 100644 --- a/app/src/lib/graph-interface/node/NodeHeader.svelte +++ b/app/src/lib/graph-interface/node/NodeHeader.svelte @@ -87,8 +87,6 @@ width: 30px; z-index: 100; border-radius: 50%; - /* background: red; */ - /* opacity: 0.2; */ } .click-target:hover + svg path { @@ -108,7 +106,9 @@ svg path { stroke-width: 0.2px; - transition: d 0.3s ease, fill 0.3s ease; + transition: + d 0.3s ease, + fill 0.3s ease; fill: var(--color-layer-2); stroke: var(--stroke); stroke-width: var(--stroke-width); diff --git a/app/src/lib/graph-interface/node/NodeInput.svelte b/app/src/lib/graph-interface/node/NodeInput.svelte index af30b89..a4a5c24 100644 --- a/app/src/lib/graph-interface/node/NodeInput.svelte +++ b/app/src/lib/graph-interface/node/NodeInput.svelte @@ -31,11 +31,24 @@ return 0; } - let value = $state(getDefaultValue()); + let value = $state(structuredClone($state.snapshot(getDefaultValue()))); + + function diffArray(a: number[], b?: number[] | number) { + if (!Array.isArray(b)) return true; + if (Array.isArray(a) !== Array.isArray(b)) return true; + if (a.length !== b.length) return true; + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return true; + } + return false; + } $effect(() => { - if (value !== undefined && node?.props?.[id] !== value) { - node.props = { ...node.props, [id]: value }; + const a = $state.snapshot(value); + const b = $state.snapshot(node?.props?.[id]); + const isDiff = Array.isArray(a) ? diffArray(a, b) : a !== b; + if (value !== undefined && isDiff) { + node.props = { ...node.props, [id]: a }; if (graph) { graph.save(); graph.execute(); diff --git a/app/src/lib/graph-interface/node/NodeParameter.svelte b/app/src/lib/graph-interface/node/NodeParameter.svelte index dc48390..0889c21 100644 --- a/app/src/lib/graph-interface/node/NodeParameter.svelte +++ b/app/src/lib/graph-interface/node/NodeParameter.svelte @@ -18,6 +18,8 @@ const inputType = $derived(node?.state?.type?.inputs?.[id]); const socketId = $derived(`${node.id}-${id}`); + const isShape = $derived(input.type === 'shape' && input.external !== true); + const height = $derived(isShape ? 200 : 100); const graphState = getGraphState(); const graphId = graph?.id; @@ -64,6 +66,7 @@ class="wrapper" data-node-type={node.type} data-node-input={id} + style:height="{height}px" class:possible-socket={graphState?.possibleSocketIds.has(socketId)} > {#key id && graphId} @@ -95,8 +98,6 @@ >(); diff --git a/app/src/lib/runtime/runtime-executor.ts b/app/src/lib/runtime/runtime-executor.ts index 51595d1..0248f25 100644 --- a/app/src/lib/runtime/runtime-executor.ts +++ b/app/src/lib/runtime/runtime-executor.ts @@ -28,7 +28,7 @@ function getValue(input: NodeInput, value?: unknown) { } if (Array.isArray(value)) { - if (input.type === 'vec3') { + if (input.type === 'vec3' || input.type === 'shape') { return [ 0, value.length + 1, diff --git a/app/src/lib/settings/NestedSettings.svelte b/app/src/lib/settings/NestedSettings.svelte index 0b7d6ff..aa59a24 100644 --- a/app/src/lib/settings/NestedSettings.svelte +++ b/app/src/lib/settings/NestedSettings.svelte @@ -211,7 +211,7 @@ .first-level.input { padding-left: 1em; padding-right: 1em; - padding-bottom: 1px; + padding-bottom: 0.5px; gap: 3px; } diff --git a/app/src/lib/settings/app-settings.svelte.ts b/app/src/lib/settings/app-settings.svelte.ts index 1720b50..3c17bf4 100644 --- a/app/src/lib/settings/app-settings.svelte.ts +++ b/app/src/lib/settings/app-settings.svelte.ts @@ -6,6 +6,7 @@ const themes = [ 'catppuccin', 'solarized', 'high-contrast', + 'high-contrast-light', 'nord', 'dracula' ] as const; @@ -29,10 +30,11 @@ export const AppSettingTypes = { }, nodeInterface: { title: 'Node Interface', - showNodeGrid: { - type: 'boolean', - label: 'Show Grid', - value: true + backgroundType: { + type: 'select', + label: 'Background', + options: ['grid', 'dots', 'none'], + value: 'grid' }, snapToGrid: { type: 'boolean', diff --git a/app/src/lib/sidebar/panels/Changelog.svelte b/app/src/lib/sidebar/panels/Changelog.svelte index 682c65f..93be63e 100644 --- a/app/src/lib/sidebar/panels/Changelog.svelte +++ b/app/src/lib/sidebar/panels/Changelog.svelte @@ -22,25 +22,10 @@ ]); function detectCommitType(commit: string) { - if (commit.startsWith('fix:') || commit.startsWith('fix(')) { - return 'fix'; - } - - if (commit.startsWith('feat:') || commit.startsWith('feat(')) { - return 'feat'; - } - - if (commit.startsWith('chore:') || commit.startsWith('chore(')) { - return 'chore'; - } - if (commit.startsWith('docs:') || commit.startsWith('docs(')) { - return 'docs'; - } - if (commit.startsWith('refactor:') || commit.startsWith('refactor(')) { - return 'refactor'; - } - if (commit.startsWith('ci:') || commit.startsWith('ci(')) { - return 'ci'; + for (const key of typeMap.keys()) { + if (commit.startsWith(key)) { + return key; + } } return ''; } @@ -152,7 +137,7 @@ {/if} -
+

@nodarium/error

+
+
{JSON.stringify(page.error, null, 2)}
+
+
+ +
+
+ diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 9fcbbc4..3747db6 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -171,7 +171,7 @@ graph={pm.graph} bind:this={graphInterface} registry={nodeRegistry} - showGrid={appSettings.value.nodeInterface.showNodeGrid} + backgroundType={appSettings.value.nodeInterface.backgroundType} snapToGrid={appSettings.value.nodeInterface.snapToGrid} bind:activeNode bind:showHelp={appSettings.value.nodeInterface.showHelp} diff --git a/nodes/max/plantarium/instance/src/input.json b/nodes/max/plantarium/instance/src/input.json index 215946e..14bd27e 100644 --- a/nodes/max/plantarium/instance/src/input.json +++ b/nodes/max/plantarium/instance/src/input.json @@ -28,6 +28,13 @@ "value": 1, "hidden": true }, + "rotation": { + "type": "float", + "min": 0, + "max": 1, + "value": 0.5, + "hidden": true + }, "depth": { "type": "integer", "min": 1, diff --git a/nodes/max/plantarium/instance/src/lib.rs b/nodes/max/plantarium/instance/src/lib.rs index ca98ac9..f522e88 100644 --- a/nodes/max/plantarium/instance/src/lib.rs +++ b/nodes/max/plantarium/instance/src/lib.rs @@ -1,12 +1,9 @@ use glam::{Mat4, Quat, Vec3}; -use nodarium_macros::nodarium_execute; -use nodarium_macros::nodarium_definition_file; +use nodarium_macros::{nodarium_execute, nodarium_definition_file}; use nodarium_utils::{ concat_args, evaluate_float, evaluate_int, - geometry::{ - create_instance_data, wrap_geometry_data, wrap_instance_data, wrap_path, - }, - log, split_args, + geometry::{create_instance_data, wrap_geometry_data, wrap_instance_data, wrap_path}, + split_args, }; nodarium_definition_file!("src/input.json"); @@ -15,13 +12,13 @@ nodarium_definition_file!("src/input.json"); pub fn execute(input: &[i32]) -> Vec { let args = split_args(input); let mut inputs = split_args(args[0]); - log!("WASM(instance): inputs: {:?}", inputs); let mut geo_data = args[1].to_vec(); let geo = wrap_geometry_data(&mut geo_data); let mut transforms: Vec = Vec::new(); + // Find max depth let mut max_depth = 0; for path_data in inputs.iter() { if path_data[2] != 0 { @@ -30,7 +27,8 @@ pub fn execute(input: &[i32]) -> Vec { max_depth = max_depth.max(path_data[3]); } - let depth = evaluate_int(args[5]); + let rotation = evaluate_float(args[5]); + let depth = evaluate_int(args[6]); for path_data in inputs.iter() { if path_data[3] < (max_depth - depth + 1) { @@ -38,24 +36,34 @@ pub fn execute(input: &[i32]) -> Vec { } let amount = evaluate_int(args[2]); - let lowest_instance = evaluate_float(args[3]); let highest_instance = evaluate_float(args[4]); let path = wrap_path(path_data); for i in 0..amount { - let alpha = - lowest_instance + (i as f32 / amount as f32) * (highest_instance - lowest_instance); + let alpha = lowest_instance + + (i as f32 / (amount - 1) as f32) * (highest_instance - lowest_instance); let point = path.get_point_at(alpha); - let direction = path.get_direction_at(alpha); + let tangent = path.get_direction_at(alpha); + let size = point[3] + 0.01; + + let axis_rotation = Quat::from_axis_angle( + Vec3::from_slice(&tangent).normalize(), + i as f32 * rotation, + ); + + let path_rotation = Quat::from_rotation_arc(Vec3::Y, Vec3::from_slice(&tangent).normalize()); + + let rotation = path_rotation * axis_rotation; let transform = Mat4::from_scale_rotation_translation( - Vec3::new(point[3], point[3], point[3]), - Quat::from_xyzw(direction[0], direction[1], direction[2], 1.0).normalize(), + Vec3::new(size, size, size), + rotation, Vec3::from_slice(&point), ); + transforms.push(transform); } } @@ -67,11 +75,11 @@ pub fn execute(input: &[i32]) -> Vec { ); let mut instances = wrap_instance_data(&mut instance_data); instances.set_geometry(geo); - (0..transforms.len()).for_each(|i| { - instances.set_transformation_matrix(i, &transforms[i].to_cols_array()); - }); - log!("WASM(instance): geo: {:?}", instance_data); + for (i, transform) in transforms.iter().enumerate() { + instances.set_transformation_matrix(i, &transform.to_cols_array()); + } + inputs.push(&instance_data); concat_args(inputs) diff --git a/nodes/max/plantarium/leaf/.gitignore b/nodes/max/plantarium/leaf/.gitignore new file mode 100644 index 0000000..4e30131 --- /dev/null +++ b/nodes/max/plantarium/leaf/.gitignore @@ -0,0 +1,6 @@ +/target +**/*.rs.bk +Cargo.lock +bin/ +pkg/ +wasm-pack.log diff --git a/nodes/max/plantarium/leaf/Cargo.toml b/nodes/max/plantarium/leaf/Cargo.toml new file mode 100644 index 0000000..b582166 --- /dev/null +++ b/nodes/max/plantarium/leaf/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "leaf" +version = "0.1.0" +authors = ["Max Richter "] +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +nodarium_macros = { version = "0.1.0", path = "../../../../packages/macros" } +nodarium_utils = { version = "0.1.0", path = "../../../../packages/utils" } diff --git a/nodes/max/plantarium/leaf/src/input.json b/nodes/max/plantarium/leaf/src/input.json new file mode 100644 index 0000000..a3a94a8 --- /dev/null +++ b/nodes/max/plantarium/leaf/src/input.json @@ -0,0 +1,24 @@ +{ + "id": "max/plantarium/leaf", + "outputs": [ + "geometry" + ], + "inputs": { + "shape": { + "type": "shape", + "external": true + }, + "size": { + "type": "float", + "value": 1 + }, + "xResolution": { + "type": "integer", + "description": "The amount of stems to produce", + "min": 1, + "max": 64, + "value": 1, + "hidden": true + } + } +} diff --git a/nodes/max/plantarium/leaf/src/lib.rs b/nodes/max/plantarium/leaf/src/lib.rs new file mode 100644 index 0000000..f48b3f1 --- /dev/null +++ b/nodes/max/plantarium/leaf/src/lib.rs @@ -0,0 +1,166 @@ +use std::convert::TryInto; +use std::f32::consts::PI; + +use nodarium_macros::nodarium_definition_file; +use nodarium_macros::nodarium_execute; +use nodarium_utils::encode_float; +use nodarium_utils::evaluate_float; +use nodarium_utils::evaluate_int; +use nodarium_utils::log; +use nodarium_utils::wrap_arg; +use nodarium_utils::{split_args, decode_float}; + +nodarium_definition_file!("src/input.json"); + +fn calculate_y(x: f32) -> f32 { + let term1 = (x * PI * 2.0).sin().abs(); + let term2 = (x * 2.0 * PI + (PI / 2.0)).sin() / 2.0; + term1 + term2 +} + +// Helper vector math functions +fn vec_sub(a: &[f32; 3], b: &[f32; 3]) -> [f32; 3] { + [a[0] - b[0], a[1] - b[1], a[2] - b[2]] +} + +fn vec_cross(a: &[f32; 3], b: &[f32; 3]) -> [f32; 3] { + [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0], + ] +} + +fn vec_normalize(v: &[f32; 3]) -> [f32; 3] { + let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt(); + if len == 0.0 { [0.0, 0.0, 0.0] } else { [v[0]/len, v[1]/len, v[2]/len] } +} + +#[nodarium_execute] +pub fn execute(input: &[i32]) -> Vec { + let args = split_args(input); + let input_path = split_args(args[0])[0]; + let size = evaluate_float(args[1]); + let width_resolution = evaluate_int(args[2]).max(3) as usize; + let path_length = (input_path.len() - 4) / 2; + + let slice_count = path_length; + let face_amount = (slice_count - 1) * (width_resolution - 1) * 2; + let position_amount = slice_count * width_resolution; + + let out_length = + 3 // metadata + + face_amount * 3 // indices + + position_amount * 3 // positions + + position_amount * 3; // normals + + let mut out = vec![0 as i32; out_length]; + + log!("face_amount={:?} position_amount={:?}", face_amount, position_amount); + + out[0] = 1; + out[1] = position_amount.try_into().unwrap(); + out[2] = face_amount.try_into().unwrap(); + let mut offset = 3; + + // Writing Indices + let mut idx = 0; + for i in 0..(slice_count - 1) { + let base0 = (i * width_resolution) as i32; + let base1 = ((i + 1) * width_resolution) as i32; + + for j in 0..(width_resolution - 1) { + let a = base0 + j as i32; + let b = base0 + j as i32 + 1; + let c = base1 + j as i32; + let d = base1 + j as i32 + 1; + + // triangle 1 + out[offset + idx + 0] = a; + out[offset + idx + 1] = b; + out[offset + idx + 2] = c; + + // triangle 2 + out[offset + idx + 3] = b; + out[offset + idx + 4] = d; + out[offset + idx + 5] = c; + + idx += 6; + } + } + + offset += face_amount * 3; + + // Writing Positions + let width = 50.0; + let mut positions = vec![[0.0f32; 3]; position_amount]; + for i in 0..slice_count { + let ax = i as f32 / (slice_count -1) as f32; + + let px = decode_float(input_path[2 + i * 2 + 0]); + let pz = decode_float(input_path[2 + i * 2 + 1]); + + + for j in 0..width_resolution { + let alpha = j as f32 / (width_resolution - 1) as f32; + let x = 2.0 * (-px * (alpha - 0.5) + alpha * width); + let py = calculate_y(alpha-0.5)*5.0*(ax*PI).sin(); + let pz_val = pz - 100.0; + + let pos_idx = i * width_resolution + j; + positions[pos_idx] = [x - width, py, pz_val]; + + let flat_idx = offset + pos_idx * 3; + out[flat_idx + 0] = encode_float((x - width) * size); + out[flat_idx + 1] = encode_float(py * size); + out[flat_idx + 2] = encode_float(pz_val * size); + } + } + + // Writing Normals + offset += position_amount * 3; + let mut normals = vec![[0.0f32; 3]; position_amount]; + + for i in 0..(slice_count - 1) { + for j in 0..(width_resolution - 1) { + let a = i * width_resolution + j; + let b = i * width_resolution + j + 1; + let c = (i + 1) * width_resolution + j; + let d = (i + 1) * width_resolution + j + 1; + + // triangle 1: a,b,c + let u = vec_sub(&positions[b], &positions[a]); + let v = vec_sub(&positions[c], &positions[a]); + let n1 = vec_cross(&u, &v); + + // triangle 2: b,d,c + let u2 = vec_sub(&positions[d], &positions[b]); + let v2 = vec_sub(&positions[c], &positions[b]); + let n2 = vec_cross(&u2, &v2); + + for &idx in &[a, b, c] { + normals[idx][0] += n1[0]; + normals[idx][1] += n1[1]; + normals[idx][2] += n1[2]; + } + + for &idx in &[b, d, c] { + normals[idx][0] += n2[0]; + normals[idx][1] += n2[1]; + normals[idx][2] += n2[2]; + } + } + } + + // normalize and write to output + for i in 0..position_amount { + let n = vec_normalize(&normals[i]); + let flat_idx = offset + i * 3; + out[flat_idx + 0] = encode_float(n[0]); + out[flat_idx + 1] = encode_float(n[1]); + out[flat_idx + 2] = encode_float(n[2]); + } + + wrap_arg(&out) +} + diff --git a/nodes/max/plantarium/shape/.gitignore b/nodes/max/plantarium/shape/.gitignore new file mode 100644 index 0000000..4e30131 --- /dev/null +++ b/nodes/max/plantarium/shape/.gitignore @@ -0,0 +1,6 @@ +/target +**/*.rs.bk +Cargo.lock +bin/ +pkg/ +wasm-pack.log diff --git a/nodes/max/plantarium/shape/Cargo.toml b/nodes/max/plantarium/shape/Cargo.toml new file mode 100644 index 0000000..19ae004 --- /dev/null +++ b/nodes/max/plantarium/shape/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "shape" +version = "0.1.0" +authors = ["Max Richter "] +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +nodarium_macros = { version = "0.1.0", path = "../../../../packages/macros" } +nodarium_utils = { version = "0.1.0", path = "../../../../packages/utils" } diff --git a/nodes/max/plantarium/shape/src/input.json b/nodes/max/plantarium/shape/src/input.json new file mode 100644 index 0000000..2b27295 --- /dev/null +++ b/nodes/max/plantarium/shape/src/input.json @@ -0,0 +1,27 @@ +{ + "id": "max/plantarium/shape", + "outputs": [ + "shape" + ], + "inputs": { + "shape": { + "type": "shape", + "internal": true, + "value": [ + 47.8, + 100, + 47.8, + 82.8, + 30.9, + 69.1, + 23.2, + 40.7, + 27.1, + 14.5, + 42.5, + 0 + ], + "label": "" + } + } +} diff --git a/nodes/max/plantarium/shape/src/lib.rs b/nodes/max/plantarium/shape/src/lib.rs new file mode 100644 index 0000000..adf2178 --- /dev/null +++ b/nodes/max/plantarium/shape/src/lib.rs @@ -0,0 +1,10 @@ +use nodarium_macros::nodarium_definition_file; +use nodarium_macros::nodarium_execute; +use nodarium_utils::{concat_args, split_args}; + +nodarium_definition_file!("src/input.json"); + +#[nodarium_execute] +pub fn execute(input: &[i32]) -> Vec { + concat_args(split_args(input)) +} diff --git a/package.json b/package.json index 4b0acb0..ae5bd6b 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "lint": "pnpm run -r --parallel lint", "format": "pnpm dprint fmt", "format:check": "pnpm dprint check", - "test": "pnpm run -r test", - "check": "pnpm run -r check", + "test": "pnpm run -r --parallel test", + "check": "pnpm run -r --parallel check", "build": "pnpm build:nodes && pnpm build:app", "build:app": "BASE_PATH=/ui pnpm -r --filter 'ui' build && pnpm -r --filter 'app' build", "build:nodes": "cargo build --workspace --target wasm32-unknown-unknown --release && rm -rf ./app/static/nodes/max/plantarium/ && mkdir -p ./app/static/nodes/max/plantarium/ && cp -R ./target/wasm32-unknown-unknown/release/*.wasm ./app/static/nodes/max/plantarium/", diff --git a/packages/types/src/inputs.ts b/packages/types/src/inputs.ts index 2dda150..c7d10ec 100644 --- a/packages/types/src/inputs.ts +++ b/packages/types/src/inputs.ts @@ -26,22 +26,32 @@ const DefaultOptionsSchema = z.object({ export const NodeInputFloatSchema = z.object({ ...DefaultOptionsSchema.shape, type: z.literal('float'), - element: z.literal('slider').optional(), value: z.number().optional(), min: z.number().optional(), max: z.number().optional(), step: z.number().optional() }); +export const NodeInputColorSchema = z.object({ + ...DefaultOptionsSchema.shape, + type: z.literal('color'), + value: z.array(z.number()).optional() +}); + export const NodeInputIntegerSchema = z.object({ ...DefaultOptionsSchema.shape, type: z.literal('integer'), - element: z.literal('slider').optional(), value: z.number().optional(), min: z.number().optional(), max: z.number().optional() }); +export const NodeInputShapeSchema = z.object({ + ...DefaultOptionsSchema.shape, + type: z.literal('shape'), + value: z.array(z.number()).optional() +}); + export const NodeInputBooleanSchema = z.object({ ...DefaultOptionsSchema.shape, type: z.literal('boolean'), @@ -83,7 +93,9 @@ export const NodeInputSchema = z.union([ NodeInputSeedSchema, NodeInputBooleanSchema, NodeInputFloatSchema, + NodeInputColorSchema, NodeInputIntegerSchema, + NodeInputShapeSchema, NodeInputSelectSchema, NodeInputSeedSchema, NodeInputVec3Schema, diff --git a/packages/types/src/lib.rs b/packages/types/src/lib.rs index 5c5262f..c8fed22 100644 --- a/packages/types/src/lib.rs +++ b/packages/types/src/lib.rs @@ -103,6 +103,15 @@ pub struct NodeInputVec3 { pub value: Option>, } +#[derive(Serialize, Deserialize)] +pub struct NodeInputShape { + #[serde(flatten)] + pub default_options: DefaultOptions, + + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option>, +} + #[derive(Serialize, Deserialize)] pub struct NodeInputGeometry { #[serde(flatten)] @@ -125,6 +134,7 @@ pub enum NodeInput { select(NodeInputSelect), seed(NodeInputSeed), vec3(NodeInputVec3), + shape(NodeInputShape), geometry(NodeInputGeometry), path(NodeInputPath), } diff --git a/packages/ui/src/lib/Details.svelte b/packages/ui/src/lib/Details.svelte index bbcb75d..1103057 100644 --- a/packages/ui/src/lib/Details.svelte +++ b/packages/ui/src/lib/Details.svelte @@ -7,14 +7,19 @@ open?: boolean; class?: string; } - let { title = 'Details', transparent = false, children, open = $bindable(false), class: _class }: - Props = $props(); + let { + title = 'Details', + transparent = false, + children, + open = $bindable(false), + class: _class + }: Props = $props();
{title}
diff --git a/packages/ui/src/lib/Input.svelte b/packages/ui/src/lib/Input.svelte index 581b585..437d35c 100644 --- a/packages/ui/src/lib/Input.svelte +++ b/packages/ui/src/lib/Input.svelte @@ -1,7 +1,14 @@