diff --git a/app/Dockerfile b/app/Dockerfile
index a059a66..3b43fbd 100644
--- a/app/Dockerfile
+++ b/app/Dockerfile
@@ -39,5 +39,6 @@ server {
EOF
COPY --from=builder /app/app/build /app
+COPY --from=builder /app/packages/ui/build /app/ui
EXPOSE 80
diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts
index 65d7012..78bd296 100644
--- a/app/src/lib/graph-interface/graph-manager.svelte.ts
+++ b/app/src/lib/graph-interface/graph-manager.svelte.ts
@@ -606,11 +606,14 @@ export class GraphManager extends EventEmitter<{
return;
}
+ const fromType = from.state.type || this.registry.getNode(from.type);
+ const toType = to.state.type || this.registry.getNode(to.type);
+
// check if socket types match
- const fromSocketType = from.state?.type?.outputs?.[fromSocket];
- const toSocketType = [to.state?.type?.inputs?.[toSocket]?.type];
- if (to.state?.type?.inputs?.[toSocket]?.accepts) {
- toSocketType.push(...(to?.state?.type?.inputs?.[toSocket]?.accepts || []));
+ const fromSocketType = fromType?.outputs?.[fromSocket];
+ const toSocketType = [toType?.inputs?.[toSocket]?.type];
+ if (toType?.inputs?.[toSocket]?.accepts) {
+ toSocketType.push(...(toType?.inputs?.[toSocket]?.accepts || []));
}
if (!areSocketsCompatible(fromSocketType, toSocketType)) {
@@ -733,9 +736,9 @@ export class GraphManager extends EventEmitter<{
}
getPossibleSockets({ node, index }: Socket): [NodeInstance, string | number][] {
- const nodeType = node?.state?.type;
- console.log({ node: $state.snapshot(node), index, nodeType });
+ const nodeType = this.registry.getNode(node.type);
if (!nodeType) return [];
+ console.log({ index });
const sockets: [NodeInstance, string | number][] = [];
@@ -750,7 +753,7 @@ export class GraphManager extends EventEmitter<{
const ownType = nodeType?.inputs?.[index].type;
for (const node of nodes) {
- const nodeType = node?.state?.type;
+ const nodeType = this.registry.getNode(node.type);
const inputs = nodeType?.outputs;
if (!inputs) continue;
for (let index = 0; index < inputs.length; index++) {
@@ -778,7 +781,7 @@ export class GraphManager extends EventEmitter<{
const ownType = nodeType.outputs?.[index];
for (const node of nodes) {
- const inputs = node?.state?.type?.inputs;
+ const inputs = this.registry.getNode(node.type)?.inputs;
if (!inputs) continue;
for (const key in inputs) {
const otherType = [inputs[key].type];
diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte
index a17769a..83478e5 100644
--- a/app/src/lib/graph-interface/node/NodeHeader.svelte
+++ b/app/src/lib/graph-interface/node/NodeHeader.svelte
@@ -43,7 +43,7 @@
- {node.type.split("/").pop()}
+ {node.type.split("/").pop()} ({node.id})
= new Map();
private offset = 0;
+ private isRunning = false;
private memory = new WebAssembly.Memory({
initial: 1024,
maximum: 8192
});
+ private memoryView = new Int32Array();
+
+ results: Record
= {};
+ inputPtrs: Record = {};
seed = 123123;
perf?: PerformanceStore;
+ public getMemory() {
+ return new Int32Array(this.memory.buffer);
+ }
+
constructor(
private registry: NodeRegistry,
public cache?: SyncCache
@@ -129,7 +147,8 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
const outputNode = graphNodes.find((node) => node.type.endsWith('/output'));
if (!outputNode) {
- throw new Error('No output node found');
+ // throw new Error('No output node found');
+ console.log('No output node found');
}
const nodeMap = new Map(
@@ -151,7 +170,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
const nodes = [];
// loop through all the nodes and assign each nodes its depth
- const stack = [outputNode];
+ const stack = [outputNode || graphNodes[0]];
while (stack.length) {
const node = stack.pop();
if (!node) continue;
@@ -166,14 +185,15 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
return [outputNode, nodes] as const;
}
- private writeToMemory(v: number | number[] | Int32Array) {
+ private writeToMemory(v: number | number[] | Int32Array, title?: string) {
let length = 1;
- const view = new Int32Array(this.memory.buffer);
+
if (typeof v === 'number') {
- view[this.offset] = v;
+ this.memoryView[this.offset] = v;
+ console.log('MEM: writing number', v, ' to', this.offset);
length = 1;
} else {
- view.set(v, this.offset);
+ this.memoryView.set(v, this.offset);
length = v.length;
}
@@ -184,15 +204,25 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
return {
start,
- end
+ end,
+ _title: title
};
}
+ private printMemory() {
+ this.memoryView = new Int32Array(this.memory.buffer);
+ console.log('MEMORY', this.memoryView.slice(0, 10));
+ }
+
async execute(graph: Graph, _settings: Record) {
this.offset = 0;
+ this.inputPtrs = {};
+ this.results = {};
+ if (this.isRunning) return undefined as unknown as Int32Array;
+ this.isRunning = true;
// Then we add some metadata to the graph
- const [outputNode, nodes] = await this.addMetaData(graph);
+ const [_outputNode, nodes] = await this.addMetaData(graph);
/*
* Here we sort the nodes into buckets, which we then execute one by one
@@ -210,14 +240,14 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
(a, b) => (b.state?.depth || 0) - (a.state?.depth || 0)
);
- // here we store the intermediate results of the nodes
- const results: Record = {};
-
for (const node of sortedNodes) {
const node_type = this.nodes.get(node.type)!;
- console.log('EXECUTING NODE', node_type.definition.id);
- console.log(node_type.definition.inputs);
+ console.log('---------------');
+ console.log('STARTING NODE EXECUTION', node_type.definition.id);
+ this.printMemory();
+
+ // console.log(node_type.definition.inputs);
const inputs = Object.entries(node_type.definition.inputs || {}).map(
([key, input]) => {
// We should probably initially write this to memory
@@ -225,6 +255,8 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
return this.writeToMemory(this.seed);
}
+ const title = `${node.id}.${key}`;
+
// We should probably initially write this to memory
// If the input is linked to a setting, we use that value
// if (input.setting) {
@@ -234,56 +266,85 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
// check if the input is connected to another node
const inputNode = node.state.inputNodes[key];
if (inputNode) {
- if (results[inputNode.id] === undefined) {
+ if (this.results[inputNode.id] === undefined) {
throw new Error(
`Node ${node.type} is missing input from node ${inputNode.type}`
);
}
- return results[inputNode.id];
+ return this.results[inputNode.id];
}
// If the value is stored in the node itself, we use that value
if (node.props?.[key] !== undefined) {
- return this.writeToMemory(getValue(input, node.props[key]));
+ const value = getValue(input, node.props[key]);
+ console.log(`Writing prop for ${node.id} -> ${key} to memory`, node.props[key], value);
+ return this.writeToMemory(value, title);
}
- return this.writeToMemory(getValue(input));
+ return this.writeToMemory(getValue(input), title);
}
);
+ this.printMemory();
+
if (!node_type || !node.state || !node_type.execute) {
log.warn(`Node ${node.id} has no definition`);
continue;
}
+ this.inputPtrs[node.id] = inputs;
const args = inputs.map(s => [s.start, s.end]).flat();
- console.log('ARGS', args);
+ console.log('ARGS', inputs);
+ this.printMemory();
try {
- const bytesWritten = node_type.execute(this.offset, args);
- results[node.id] = {
- start: this.offset,
- end: this.offset + bytesWritten
- };
- this.offset += bytesWritten;
+ console.log('EXECUTING NODE, writing output of node to ->', this.offset);
+ const bytesWritten = node_type.execute(this.offset * 4, args.map(a => a * 4));
+ const view = new Int32Array(this.memory.buffer);
+
+ const input = view.slice(args[0], args[1]);
+ const output = view.slice(this.offset, this.offset + bytesWritten / 4);
+ console.log('RESULT', { args, input, output });
+
+ // Optimization
+ // If the input arg is the same length as the output arg
+ if (
+ args.length === 2 && args[1] - args[0] == bytesWritten / 4 && compareInt32(input, output)
+ ) {
+ console.log('INPUT === OUTPUT');
+ this.results[node.id] = {
+ start: args[0],
+ end: args[1],
+ _title: `${node.id} ->`
+ };
+ } else {
+ this.results[node.id] = {
+ start: this.offset,
+ end: this.offset + bytesWritten / 4,
+ _title: `${node.id} ->`
+ };
+ this.offset += bytesWritten / 4;
+ }
console.log('FINISHED EXECUTION', {
bytesWritten,
offset: this.offset
});
} catch (e) {
- console.error(e);
+ console.error(`Failed to execute node ${node.type}/${node.id}`, e);
+ this.isRunning = false;
}
}
- const mem = new Int32Array(this.memory.buffer);
- console.log('OUT', mem.slice(0, 10));
+ // const mem = new Int32Array(this.memory.buffer);
+ // console.log('OUT', mem.slice(0, 10));
// return the result of the parent of the output node
- const res = results[outputNode.id];
+ // const res = this.results[outputNode.id];
this.perf?.endPoint('runtime');
- return res as unknown as Int32Array;
+ this.isRunning = false;
+ return undefined as unknown as Int32Array;
}
getPerformanceData() {
diff --git a/app/src/routes/dev/+page.svelte b/app/src/routes/dev/+page.svelte
index 24e01b5..0e8ae01 100644
--- a/app/src/routes/dev/+page.svelte
+++ b/app/src/routes/dev/+page.svelte
@@ -1,16 +1,14 @@
+ ev.key === "r" && handleResult()}
+/>
+
- {#if result}
- {JSON.stringify(decodeNestedArray(result))}
+ {#if visibleRows?.length}
+
+
{/if}
+ {#if isCalculating}
+
+ {/if}
+
handleSave(g)}
- onresult={(result) => handleResult(result)}
+ onresult={(res) => handleResult(res)}
/>
diff --git a/nodes/max/plantarium/box/src/lib.rs b/nodes/max/plantarium/box/src/lib.rs
index e4dc8f4..5802fd1 100644
--- a/nodes/max/plantarium/box/src/lib.rs
+++ b/nodes/max/plantarium/box/src/lib.rs
@@ -3,18 +3,17 @@ use nodarium_macros::nodarium_execute;
use nodarium_utils::{
encode_float, evaluate_float, geometry::calculate_normals,log,
split_args, wrap_arg,
+ read_i32_slice
};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
+pub fn execute(size: (i32, i32)) -> Vec {
- let args = split_args(input);
+ let args = read_i32_slice(size);
- log!("WASM(cube): input: {:?} -> {:?}", input, args);
-
- let size = evaluate_float(args[0]);
+ let size = evaluate_float(&args);
let p = encode_float(size);
let n = encode_float(-size);
@@ -77,8 +76,6 @@ pub fn execute(input: &[i32]) -> Vec {
let res = wrap_arg(&cube_geometry);
- log!("WASM(box): output: {:?}", res);
-
res
}
diff --git a/nodes/max/plantarium/branch/src/lib.rs b/nodes/max/plantarium/branch/src/lib.rs
index 6f9b60d..b5d296a 100644
--- a/nodes/max/plantarium/branch/src/lib.rs
+++ b/nodes/max/plantarium/branch/src/lib.rs
@@ -1,5 +1,6 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
+use nodarium_utils::read_i32_slice;
use nodarium_utils::{
concat_arg_vecs, evaluate_float, evaluate_int,
geometry::{
@@ -13,15 +14,25 @@ use std::f32::consts::PI;
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
- let args = split_args(input);
-
- let paths = split_args(args[0]);
+pub fn execute(
+ path: (i32, i32),
+ length: (i32, i32),
+ thickness: (i32, i32),
+ offset_single: (i32, i32),
+ lowest_branch: (i32, i32),
+ highest_branch: (i32, i32),
+ depth: (i32, i32),
+ amount: (i32, i32),
+ resolution_curve: (i32, i32),
+ rotation: (i32, i32),
+) -> Vec {
+ let arg = read_i32_slice(path);
+ let paths = split_args(arg.as_slice());
let mut output: Vec> = Vec::new();
- let resolution = evaluate_int(args[8]).max(4) as usize;
- let depth = evaluate_int(args[6]);
+ let resolution = evaluate_int(read_i32_slice(resolution_curve).as_slice()).max(4) as usize;
+ let depth = evaluate_int(read_i32_slice(depth).as_slice());
let mut max_depth = 0;
for path_data in paths.iter() {
@@ -40,18 +51,18 @@ pub fn execute(input: &[i32]) -> Vec {
let path = wrap_path(path_data);
- let branch_amount = evaluate_int(args[7]).max(1);
+ let branch_amount = evaluate_int(read_i32_slice(amount).as_slice()).max(1);
- let lowest_branch = evaluate_float(args[4]);
- let highest_branch = evaluate_float(args[5]);
+ let lowest_branch = evaluate_float(read_i32_slice(lowest_branch).as_slice());
+ let highest_branch = evaluate_float(read_i32_slice(highest_branch).as_slice());
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 length = evaluate_float(read_i32_slice(length).as_slice());
+ let thickness = evaluate_float(read_i32_slice(thickness).as_slice());
let offset_single = if i % 2 == 0 {
- evaluate_float(args[3])
+ evaluate_float(read_i32_slice(offset_single).as_slice())
} else {
0.0
};
@@ -65,7 +76,8 @@ pub fn execute(input: &[i32]) -> Vec {
root_alpha + (offset_single - 0.5) * 6.0 / resolution as f32,
);
- let rotation_angle = (evaluate_float(args[9]) * PI / 180.0) * i as f32;
+ let rotation_angle =
+ (evaluate_float(read_i32_slice(rotation).as_slice()) * PI / 180.0) * i as f32;
// check if diration contains NaN
if orthogonal[0].is_nan() || orthogonal[1].is_nan() || orthogonal[2].is_nan() {
diff --git a/nodes/max/plantarium/float/src/lib.rs b/nodes/max/plantarium/float/src/lib.rs
index 6872713..77da6ca 100644
--- a/nodes/max/plantarium/float/src/lib.rs
+++ b/nodes/max/plantarium/float/src/lib.rs
@@ -1,11 +1,11 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
-use nodarium_utils::log;
+use nodarium_utils::{ log, read_f32, encode_float };
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(_value: *const i32) -> Vec {
- log!("Duuuude");
- vec![32]
+pub fn execute(a: (i32, i32)) -> Vec {
+ let a_val = read_f32(a.0);
+ vec![encode_float(a_val)]
}
diff --git a/nodes/max/plantarium/gravity/src/lib.rs b/nodes/max/plantarium/gravity/src/lib.rs
index 4453934..e656153 100644
--- a/nodes/max/plantarium/gravity/src/lib.rs
+++ b/nodes/max/plantarium/gravity/src/lib.rs
@@ -1,6 +1,7 @@
use glam::Vec3;
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
+use nodarium_utils::read_i32_slice;
use nodarium_utils::{
concat_args, evaluate_float, evaluate_int,
geometry::{wrap_path, wrap_path_mut},
@@ -14,13 +15,17 @@ fn lerp_vec3(a: Vec3, b: Vec3, t: f32) -> Vec3 {
}
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
+pub fn execute(
+ plant: (i32, i32),
+ strength: (i32, i32),
+ curviness: (i32, i32),
+ depth: (i32, i32),
+) -> Vec {
reset_call_count();
- let args = split_args(input);
-
- let plants = split_args(args[0]);
- let depth = evaluate_int(args[3]);
+ let arg = read_i32_slice(plant);
+ let plants = split_args(arg.as_slice());
+ let depth = evaluate_int(read_i32_slice(depth).as_slice());
let mut max_depth = 0;
for path_data in plants.iter() {
@@ -55,9 +60,9 @@ pub fn execute(input: &[i32]) -> Vec {
let length = direction.length();
- let curviness = evaluate_float(args[2]);
- let strength =
- evaluate_float(args[1]) / curviness.max(0.0001) * evaluate_float(args[1]);
+ let str = evaluate_float(read_i32_slice(strength).as_slice());
+ let curviness = evaluate_float(read_i32_slice(curviness).as_slice());
+ let strength = str / curviness.max(0.0001) * str;
log!(
"length: {}, curviness: {}, strength: {}",
diff --git a/nodes/max/plantarium/instance/src/lib.rs b/nodes/max/plantarium/instance/src/lib.rs
index ca98ac9..59e103f 100644
--- a/nodes/max/plantarium/instance/src/lib.rs
+++ b/nodes/max/plantarium/instance/src/lib.rs
@@ -1,23 +1,29 @@
use glam::{Mat4, Quat, Vec3};
-use nodarium_macros::nodarium_execute;
use nodarium_macros::nodarium_definition_file;
+use nodarium_macros::nodarium_execute;
+use nodarium_utils::read_i32_slice;
use nodarium_utils::{
concat_args, evaluate_float, evaluate_int,
- geometry::{
- create_instance_data, wrap_geometry_data, wrap_instance_data, wrap_path,
- },
+ geometry::{create_instance_data, wrap_geometry_data, wrap_instance_data, wrap_path},
log, split_args,
};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
- let args = split_args(input);
- let mut inputs = split_args(args[0]);
+pub fn execute(
+ plant: (i32, i32),
+ geometry: (i32, i32),
+ amount: (i32, i32),
+ lowest_instance: (i32, i32),
+ highest_instance: (i32, i32),
+ depth: (i32, i32),
+) -> Vec {
+ let arg = read_i32_slice(plant);
+ let mut inputs = split_args(arg.as_slice());
log!("WASM(instance): inputs: {:?}", inputs);
- let mut geo_data = args[1].to_vec();
+ let mut geo_data = read_i32_slice(geometry);
let geo = wrap_geometry_data(&mut geo_data);
let mut transforms: Vec = Vec::new();
@@ -30,17 +36,17 @@ pub fn execute(input: &[i32]) -> Vec {
max_depth = max_depth.max(path_data[3]);
}
- let depth = evaluate_int(args[5]);
+ let depth = evaluate_int(read_i32_slice(depth).as_slice());
for path_data in inputs.iter() {
if path_data[3] < (max_depth - depth + 1) {
continue;
}
- let amount = evaluate_int(args[2]);
+ let amount = evaluate_int(read_i32_slice(amount).as_slice());
- let lowest_instance = evaluate_float(args[3]);
- let highest_instance = evaluate_float(args[4]);
+ let lowest_instance = evaluate_float(read_i32_slice(lowest_instance).as_slice());
+ let highest_instance = evaluate_float(read_i32_slice(highest_instance).as_slice());
let path = wrap_path(path_data);
diff --git a/nodes/max/plantarium/math/src/lib.rs b/nodes/max/plantarium/math/src/lib.rs
index 27bd4ce..9ebc3a3 100644
--- a/nodes/max/plantarium/math/src/lib.rs
+++ b/nodes/max/plantarium/math/src/lib.rs
@@ -1,24 +1,13 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
-use nodarium_utils::{read_f32, read_i32, log};
+use nodarium_utils::{concat_arg_vecs, encode_float, log, read_i32_slice};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(op_type: *const i32, a: *const i32, b: *const i32) -> Vec {
- let op = unsafe { read_i32(op_type) };
- let a_val = unsafe { read_f32(a) };
- let b_val = unsafe { read_f32(b) };
-
- log!("op_type: {:?}", op);
-
- let result = match op {
- 0 => a_val + b_val,
- 1 => a_val - b_val,
- 2 => a_val * b_val,
- 3 => a_val / b_val,
- _ => 0.0,
- };
-
- vec![result.to_bits() as i32]
+pub fn execute(op_type: (i32, i32), a: (i32, i32), b: (i32, i32)) -> Vec {
+ let op = read_i32_slice(op_type);
+ let a_val = read_i32_slice(a);
+ let b_val = read_i32_slice(b);
+ concat_arg_vecs(vec![vec![0], op, a_val, b_val])
}
diff --git a/nodes/max/plantarium/noise/src/lib.rs b/nodes/max/plantarium/noise/src/lib.rs
index b54f684..7beb625 100644
--- a/nodes/max/plantarium/noise/src/lib.rs
+++ b/nodes/max/plantarium/noise/src/lib.rs
@@ -1,7 +1,8 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
+use nodarium_utils::read_i32_slice;
use nodarium_utils::{
- concat_args, evaluate_float, evaluate_int, evaluate_vec3, geometry::wrap_path_mut,
+ concat_args, evaluate_float, evaluate_int, evaluate_vec3, geometry::wrap_path_mut, read_i32,
reset_call_count, split_args,
};
use noise::{HybridMulti, MultiFractal, NoiseFn, OpenSimplex};
@@ -13,23 +14,31 @@ fn lerp(a: f32, b: f32, t: f32) -> f32 {
}
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
+pub fn execute(
+ plant: (i32, i32),
+ scale: (i32, i32),
+ strength: (i32, i32),
+ fix_bottom: (i32, i32),
+ seed: (i32, i32),
+ directional_strength: (i32, i32),
+ depth: (i32, i32),
+ octaves: (i32, i32),
+) -> Vec {
reset_call_count();
- let args = split_args(input);
+ let arg = read_i32_slice(plant);
+ let plants = split_args(arg.as_slice());
+ let scale = (evaluate_float(read_i32_slice(scale).as_slice()) * 0.1) as f64;
+ let strength = evaluate_float(read_i32_slice(strength).as_slice());
+ let fix_bottom = evaluate_float(read_i32_slice(fix_bottom).as_slice());
- 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]);
+ let seed = read_i32(seed.0);
- let seed = args[4][0];
+ let directional_strength = evaluate_vec3(read_i32_slice(directional_strength).as_slice());
- let directional_strength = evaluate_vec3(args[5]);
+ let depth = evaluate_int(read_i32_slice(depth).as_slice());
- let depth = evaluate_int(args[6]);
-
- let octaves = evaluate_int(args[7]);
+ let octaves = evaluate_int(read_i32_slice(octaves).as_slice());
let noise_x: HybridMulti =
HybridMulti::new(seed as u32 + 1).set_octaves(octaves as usize);
diff --git a/nodes/max/plantarium/output/src/lib.rs b/nodes/max/plantarium/output/src/lib.rs
index 90d1cd6..9b2f4b3 100644
--- a/nodes/max/plantarium/output/src/lib.rs
+++ b/nodes/max/plantarium/output/src/lib.rs
@@ -1,9 +1,14 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
+use nodarium_utils::log;
+use nodarium_utils::read_i32_slice;
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(_input: *const i32, _res: *const i32) -> Vec {
- return vec![0];
+pub fn execute(input: (i32, i32), _res: (i32, i32)) -> Vec {
+ log!("HERE");
+ let mut vecs = read_i32_slice(input);
+ vecs.push(42);
+ vecs
}
diff --git a/nodes/max/plantarium/random/src/definition.json b/nodes/max/plantarium/random/src/input.json
similarity index 100%
rename from nodes/max/plantarium/random/src/definition.json
rename to nodes/max/plantarium/random/src/input.json
diff --git a/nodes/max/plantarium/random/src/lib.rs b/nodes/max/plantarium/random/src/lib.rs
index 3937c50..3ef724d 100644
--- a/nodes/max/plantarium/random/src/lib.rs
+++ b/nodes/max/plantarium/random/src/lib.rs
@@ -1,11 +1,16 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
-use nodarium_utils::{concat_args, split_args};
+use nodarium_utils::concat_arg_vecs;
+use nodarium_utils::read_i32_slice;
-nodarium_definition_file!("src/definition.json");
+nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(args: &[i32]) -> Vec {
- let args = split_args(args);
- concat_args(vec![&[1], args[0], args[1], args[2]])
+pub fn execute(min: (i32, i32), max: (i32, i32), seed: (i32, i32)) -> Vec {
+ concat_arg_vecs(vec![
+ vec![1],
+ read_i32_slice(min),
+ read_i32_slice(max),
+ read_i32_slice(seed),
+ ])
}
diff --git a/nodes/max/plantarium/rotate/src/lib.rs b/nodes/max/plantarium/rotate/src/lib.rs
index ad2bd70..366c891 100644
--- a/nodes/max/plantarium/rotate/src/lib.rs
+++ b/nodes/max/plantarium/rotate/src/lib.rs
@@ -1,23 +1,26 @@
use glam::{Mat4, Vec3};
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
+use nodarium_utils::read_i32_slice;
use nodarium_utils::{
- concat_args, evaluate_float, evaluate_int, geometry::wrap_path_mut, log,
- split_args,
+ concat_args, evaluate_float, evaluate_int, geometry::wrap_path_mut, log, split_args,
};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
+pub fn execute(
+ plant: (i32, i32),
+ axis: (i32, i32),
+ angle: (i32, i32),
+ spread: (i32, i32),
+) -> Vec {
+ log!("DEBUG args: {:?}", plant);
- log!("DEBUG args: {:?}", input);
-
- let args = split_args(input);
-
- let plants = split_args(args[0]);
- let axis = evaluate_int(args[1]); // 0 =x, 1 = y, 2 = z
- let spread = evaluate_int(args[3]);
+ let arg = read_i32_slice(plant);
+ let plants = split_args(arg.as_slice());
+ let axis = evaluate_int(read_i32_slice(axis).as_slice()); // 0 =x, 1 = y, 2 = z
+ let spread = evaluate_int(read_i32_slice(spread).as_slice());
let output: Vec> = plants
.iter()
@@ -32,7 +35,7 @@ pub fn execute(input: &[i32]) -> Vec {
let path = wrap_path_mut(&mut path_data);
- let angle = evaluate_float(args[2]);
+ let angle = evaluate_float(read_i32_slice(angle).as_slice());
let origin = [path.points[0], path.points[1], path.points[2]];
diff --git a/nodes/max/plantarium/stem/src/lib.rs b/nodes/max/plantarium/stem/src/lib.rs
index 32e57e6..d962126 100644
--- a/nodes/max/plantarium/stem/src/lib.rs
+++ b/nodes/max/plantarium/stem/src/lib.rs
@@ -4,29 +4,28 @@ use nodarium_utils::{
evaluate_float, evaluate_int, evaluate_vec3,
geometry::{create_multiple_paths, wrap_multiple_paths},
log, reset_call_count, split_args,
+ read_i32_slice, read_i32,
};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
+pub fn execute(origin: (i32, i32), _amount: (i32,i32), length: (i32, i32), thickness: (i32, i32), resolution_curve: (i32, i32)) -> Vec {
reset_call_count();
- let args = split_args(input);
+ let amount = evaluate_int(read_i32_slice(_amount).as_slice()) as usize;
+ let path_resolution = read_i32(resolution_curve.0) as usize;
- let amount = evaluate_int(args[1]) as usize;
- let path_resolution = evaluate_int(args[4]) as usize;
-
- log!("stem args: {:?}", args);
+ log!("stem args: amount={:?}", amount);
let mut stem_data = create_multiple_paths(amount, path_resolution, 1);
let mut stems = wrap_multiple_paths(&mut stem_data);
for stem in stems.iter_mut() {
- let origin = evaluate_vec3(args[0]);
- let length = evaluate_float(args[2]);
- let thickness = evaluate_float(args[3]);
+ let origin = evaluate_vec3(read_i32_slice(origin).as_slice());
+ let length = evaluate_float(read_i32_slice(length).as_slice());
+ let thickness = evaluate_float(read_i32_slice(thickness).as_slice());
let amount_points = stem.points.len() / 4;
for i in 0..amount_points {
diff --git a/nodes/max/plantarium/triangle/src/lib.rs b/nodes/max/plantarium/triangle/src/lib.rs
index e14533c..065c37d 100644
--- a/nodes/max/plantarium/triangle/src/lib.rs
+++ b/nodes/max/plantarium/triangle/src/lib.rs
@@ -1,45 +1,48 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
-use nodarium_utils::{
- decode_float, encode_float, evaluate_int, split_args, wrap_arg, log
-};
+use nodarium_utils::read_i32_slice;
+use nodarium_utils::{decode_float, encode_float, evaluate_int, log, split_args, wrap_arg};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
-
- let args = split_args(input);
-
- let size = evaluate_int(args[0]);
+pub fn execute(size: (i32, i32)) -> Vec {
+ let size = evaluate_int(read_i32_slice(size).as_slice());
let decoded = decode_float(size);
let negative_size = encode_float(-decoded);
- log!("WASM(triangle): input: {:?} -> {}", args[0],decoded);
+ log!("WASM(triangle): input: {:?} -> {}", size, decoded);
// [[1,3, x, y, z, x, y,z,x,y,z]];
wrap_arg(&[
- 1, // 1: geometry
- 3, // 3 vertices
- 1, // 1 face
+ 1, // 1: geometry
+ 3, // 3 vertices
+ 1, // 1 face
// this are the indeces for the face
- 0, 2, 1,
+ 0,
+ 2,
+ 1,
//
- negative_size, // x -> point 1
- 0, // y
- 0, // z
+ negative_size, // x -> point 1
+ 0, // y
+ 0, // z
//
- size, // x -> point 2
- 0, // y
- 0, // z
+ size, // x -> point 2
+ 0, // y
+ 0, // z
//
- 0, // x -> point 3
- 0, // y
- size, // z
+ 0, // x -> point 3
+ 0, // y
+ size, // z
// this is the normal for the single face 1065353216 == 1.0f encoded is i32
- 0, 1065353216, 0,
- 0, 1065353216, 0,
- 0, 1065353216, 0,
+ 0,
+ 1065353216,
+ 0,
+ 0,
+ 1065353216,
+ 0,
+ 0,
+ 1065353216,
+ 0,
])
-
}
diff --git a/nodes/max/plantarium/vec3/src/lib.rs b/nodes/max/plantarium/vec3/src/lib.rs
index 118fd29..a6d0dae 100644
--- a/nodes/max/plantarium/vec3/src/lib.rs
+++ b/nodes/max/plantarium/vec3/src/lib.rs
@@ -1,13 +1,16 @@
use nodarium_macros::nodarium_definition_file;
use nodarium_macros::nodarium_execute;
+use nodarium_utils::concat_arg_vecs;
+use nodarium_utils::read_i32_slice;
use nodarium_utils::{concat_args, log, split_args};
nodarium_definition_file!("src/input.json");
#[nodarium_execute]
-pub fn execute(input: &[i32]) -> Vec {
- let args = split_args(input);
- log!("vec3 input: {:?}", input);
- log!("vec3 args: {:?}", args);
- concat_args(args)
+pub fn execute(x: (i32, i32), y: (i32, i32), z: (i32, i32)) -> Vec {
+ concat_arg_vecs(vec![
+ read_i32_slice(x),
+ read_i32_slice(y),
+ read_i32_slice(z),
+ ])
}
diff --git a/packages/macros/src/lib.rs b/packages/macros/src/lib.rs
index 385c63d..81b0d2f 100644
--- a/packages/macros/src/lib.rs
+++ b/packages/macros/src/lib.rs
@@ -68,40 +68,48 @@ pub fn nodarium_execute(_attr: TokenStream, item: TokenStream) -> TokenStream {
})
.collect();
- let arg_names: Vec<_> = (0..input_count)
+ let param_count = input_fn.sig.inputs.len();
+ let total_c_params = param_count * 2;
+
+ let arg_names: Vec<_> = (0..total_c_params)
.map(|i| syn::Ident::new(&format!("arg{}", i), input_fn.sig.span()))
.collect();
+ let mut tuple_args = Vec::new();
+ for i in 0..param_count {
+ let start_name = &arg_names[i * 2];
+ let end_name = &arg_names[i * 2 + 1];
+ let tuple_arg = quote! {
+ (#start_name, #end_name)
+ };
+ tuple_args.push(tuple_arg);
+ }
+
let expanded = quote! {
+
extern "C" {
fn __nodarium_log(ptr: *const u8, len: usize);
fn __nodarium_log_panic(ptr: *const u8, len: usize);
}
- #fn_vis fn #inner_fn_name(#( #input_param_names: *const i32 ),*) -> Vec {
+ #fn_vis fn #inner_fn_name(#( #input_param_names: (i32, i32) ),*) -> Vec {
#fn_body
}
#[no_mangle]
#fn_vis extern "C" fn execute(output_pos: i32, #( #arg_names: i32 ),*) -> i32 {
- static PANIC_HOOK_SET: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
-
- if !PANIC_HOOK_SET.load(std::sync::atomic::Ordering::SeqCst) {
- std::panic::set_hook(Box::new(|info| {
- let msg = info.to_string();
- unsafe { __nodarium_log_panic(msg.as_ptr(), msg.len()); }
- }));
- PANIC_HOOK_SET.store(true, std::sync::atomic::Ordering::SeqCst);
- }
+ // log!("before_fn");
let result = #inner_fn_name(
- #( #arg_names as *const i32 ),*
+ #( #tuple_args ),*
);
+ // log!("after_fn");
let len_bytes = result.len() * 4;
unsafe {
let src = result.as_ptr() as *const u8;
let dst = output_pos as *mut u8;
+ // log!("writing output_pos={:?} src={:?} len_bytes={:?}", output_pos, src, len_bytes);
dst.copy_from_nonoverlapping(src, len_bytes);
}
@@ -116,7 +124,9 @@ pub fn nodarium_execute(_attr: TokenStream, item: TokenStream) -> TokenStream {
fn validate_signature(fn_sig: &syn::Signature, expected_inputs: usize, def: &NodeDefinition) {
let param_count = fn_sig.inputs.len();
- if param_count != expected_inputs {
+ let expected_params = expected_inputs;
+
+ if param_count != expected_params {
panic!(
"Execute function has {} parameters but definition has {} inputs\n\
Definition inputs: {:?}\n\
@@ -129,12 +139,36 @@ fn validate_signature(fn_sig: &syn::Signature, expected_inputs: usize, def: &Nod
.map(|i| i.keys().collect::>())
.unwrap_or_default(),
(0..expected_inputs)
- .map(|i| format!("arg{}: *const i32", i))
+ .map(|i| format!("arg{}: (i32, i32)", i))
.collect::>()
.join(", ")
);
}
+ for (i, arg) in fn_sig.inputs.iter().enumerate() {
+ match arg {
+ syn::FnArg::Typed(pat_type) => {
+ let type_str = quote! { #pat_type.ty }.to_string();
+ let clean_type = type_str
+ .trim()
+ .trim_start_matches("_")
+ .trim_end_matches(".ty")
+ .trim()
+ .to_string();
+ if !clean_type.contains("(") && !clean_type.contains(",") {
+ panic!(
+ "Parameter {} has type '{}' but should be a tuple (i32, i32) representing (start, end) positions in memory",
+ i,
+ clean_type
+ );
+ }
+ }
+ syn::FnArg::Receiver(_) => {
+ panic!("Execute function cannot have 'self' parameter");
+ }
+ }
+ }
+
match &fn_sig.output {
syn::ReturnType::Type(_, ty) => {
let is_vec = match &**ty {
diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts
index 0203104..2586369 100644
--- a/packages/types/src/types.ts
+++ b/packages/types/src/types.ts
@@ -21,7 +21,7 @@ export type NodeRuntimeState = {
parents?: NodeInstance[];
children?: NodeInstance[];
inputNodes?: Record;
- type?: NodeDefinition;
+ type?: NodeDefinition; // we should probably remove this and rely on registry.getNode(nodeType)
downX?: number;
downY?: number;
x?: number;
diff --git a/packages/utils/src/encoding.rs b/packages/utils/src/encoding.rs
index 4b7f7c9..6cc3bb0 100644
--- a/packages/utils/src/encoding.rs
+++ b/packages/utils/src/encoding.rs
@@ -11,51 +11,38 @@ pub fn decode_float(bits: i32) -> f32 {
}
#[inline]
-pub unsafe fn read_i32(ptr: *const i32) -> i32 {
- *ptr
-}
-
-#[inline]
-pub unsafe fn read_f32(ptr: *const i32) -> f32 {
- f32::from_bits(*ptr as u32)
-}
-
-#[inline]
-pub unsafe fn read_bool(ptr: *const i32) -> bool {
- *ptr != 0
-}
-
-#[inline]
-pub unsafe fn read_vec3(ptr: *const i32) -> [f32; 3] {
- let p = ptr as *const f32;
- [p.read(), p.add(1).read(), p.add(2).read()]
-}
-
-#[inline]
-pub unsafe fn read_i32_slice(ptr: *const i32, len: usize) -> Vec {
- std::slice::from_raw_parts(ptr, len).to_vec()
-}
-
-#[inline]
-pub unsafe fn read_f32_slice(ptr: *const i32, len: usize) -> Vec {
- std::slice::from_raw_parts(ptr as *const f32, len).to_vec()
-}
-
-#[inline]
-pub unsafe fn read_f32_default(ptr: *const i32, default: f32) -> f32 {
- if ptr.is_null() {
- default
- } else {
- read_f32(ptr)
+pub fn read_i32(ptr: i32) -> i32 {
+ unsafe {
+ let _ptr = ptr as *const i32;
+ *_ptr
}
}
#[inline]
-pub unsafe fn read_i32_default(ptr: *const i32, default: i32) -> i32 {
- if ptr.is_null() {
- default
- } else {
- read_i32(ptr)
+pub fn read_f32(ptr: i32) -> f32 {
+ unsafe {
+ let _ptr = ptr as *const i32;
+ f32::from_bits(*_ptr as u32)
+ }
+}
+
+#[inline]
+pub fn read_i32_slice(tuple: (i32, i32)) -> Vec {
+ unsafe {
+ let start = tuple.0 as *const i32;
+ let end = tuple.1 as *const i32;
+ let len = (end as usize - start as usize) / 4;
+ std::slice::from_raw_parts(start, len).to_vec()
+ }
+}
+
+#[inline]
+pub fn read_f32_slice(tuple: (i32, i32)) -> Vec {
+ unsafe {
+ let start = tuple.0 as *const f32;
+ let end = tuple.1 as *const f32;
+ let len = (end as usize - start as usize) / 4;
+ std::slice::from_raw_parts(start, len).to_vec()
}
}
diff --git a/packages/utils/src/wasm-wrapper.ts b/packages/utils/src/wasm-wrapper.ts
index 0a56ea8..5d163d8 100644
--- a/packages/utils/src/wasm-wrapper.ts
+++ b/packages/utils/src/wasm-wrapper.ts
@@ -27,7 +27,6 @@ export function createWasmWrapper(buffer: ArrayBuffer, memory: WebAssembly.Memor
exports = instance.exports as NodariumExports;
function execute(outputPos: number, args: number[]): number {
- console.log('WASM_WRAPPER', { outputPos, args });
return exports.execute(outputPos, ...args);
}