feat: add box node

This commit is contained in:
max_richter 2024-04-17 15:34:28 +02:00
parent ddd0e6a0cf
commit 7579c6c00b
24 changed files with 364 additions and 99 deletions

16
Cargo.lock generated
View File

@ -16,6 +16,20 @@ dependencies = [
"web-sys",
]
[[package]]
name = "box"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "bumpalo"
version = "3.16.0"
@ -329,11 +343,13 @@ name = "triangle"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]

View File

@ -8,6 +8,13 @@ import type { NodeInput } from "@nodes/types";
const logger = createLogger("graph-manager");
function areSocketsCompatible(output: string | undefined, inputs: string | string[] | undefined) {
if (Array.isArray(inputs) && output) {
return inputs.includes(output);
}
return inputs === output;
}
export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }> {
status: Writable<"loading" | "idle" | "error"> = writable("loading");
@ -177,7 +184,6 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
}
}
}
console.log(settings);
this.history.reset();
this._init(this.graph);
@ -353,7 +359,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
const fromSocketType = from.tmp?.type?.outputs?.[fromSocket];
const toSocketType = to.tmp?.type?.inputs?.[toSocket]?.type;
if (fromSocketType !== toSocketType) {
if (!areSocketsCompatible(fromSocketType, toSocketType)) {
logger.error(`Socket types do not match: ${fromSocketType} !== ${toSocketType}`);
return;
}
@ -441,8 +447,8 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
const nodeType = node?.tmp?.type;
if (!nodeType) return [];
const sockets: [Node, string | number][] = []
// if index is a string, we are an input looking for outputs
if (typeof index === "string") {
@ -479,7 +485,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
const inputs = node?.tmp?.type?.inputs;
if (!inputs) continue;
for (const key in inputs) {
if (inputs[key].type === ownType && edges.get(node.id) !== key) {
if (areSocketsCompatible(ownType, inputs[key].type) && edges.get(node.id) !== key) {
sockets.push([node, key]);
}
}

View File

@ -72,10 +72,13 @@ export class RemoteNodeRegistry implements NodeRegistry {
nodeIds.push("max/plantarium/random");
nodeIds.push("max/plantarium/float");
nodeIds.push("max/plantarium/triangle");
nodeIds.push("max/plantarium/output");
nodeIds.push("max/plantarium/array");
nodeIds.push("max/plantarium/sum");
nodeIds.push("max/plantarium/stem");
nodeIds.push("max/plantarium/box");
nodeIds.push("max/plantarium/math");
const nodes = await Promise.all(nodeIds.map(id => this.loadNode(id)));

View File

@ -1,18 +1,38 @@
<script lang="ts">
import { T } from "@threlte/core";
import { Text } from "@threlte/extras";
import type { BufferGeometry } from "three";
import { OrbitControls } from "@threlte/extras";
export let geometry: BufferGeometry[];
function getPosition(geo: BufferGeometry, i: number) {
const pos = [
geo.attributes.position.array[i],
geo.attributes.position.array[i + 1],
geo.attributes.position.array[i + 2],
];
return pos;
}
</script>
<T.PerspectiveCamera position={[10, 10, 10]} makeDefault fov={50}>
<T.PerspectiveCamera position={[-10, 10, 10]} makeDefault fov={50}>
<OrbitControls />
</T.PerspectiveCamera>
<T.DirectionalLight position={[0, 10, 10]} />
{#each geometry as geo}
{#each geo.attributes.position.array as attr, i}
{#if i % 3 === 0}
<Text text={i / 3} fontSize={1} position={getPosition(geo, i)} />
{/if}
{/each}
<T.Points visible={true}>
<T is={geo} />
<T.PointsMaterial size={0.25} />
</T.Points>
<T.Mesh geometry={geo}>
<T.MeshBasicMaterial color="red" />
</T.Mesh>

View File

@ -1,7 +1,11 @@
<script lang="ts">
import { Canvas } from "@threlte/core";
import Scene from "./Scene.svelte";
import { BufferGeometry, Float32BufferAttribute } from "three";
import {
BufferAttribute,
BufferGeometry,
Float32BufferAttribute,
} from "three";
import { decodeFloat } from "$lib/helpers/encode";
export let result: Int32Array;
@ -20,33 +24,28 @@
const faceCount = encodedData[index++];
// Indices
const indices: number[] = [];
for (let i = 0; i < faceCount * 3; i++) {
indices.push(encodedData[index++]);
}
const indices = encodedData.subarray(index, index + faceCount * 3);
index = index + faceCount * 3;
// Face normals (although typically there would be one normal per vertex)
const normals: number[] = [];
for (let i = 0; i < faceCount; i++) {
const x = decodeFloat(encodedData[index++]);
const y = decodeFloat(encodedData[index++]);
const z = decodeFloat(encodedData[index++]);
normals.push(x, y, z);
}
const normals = new Float32Array(
encodedData.buffer,
index * 4,
faceCount * 3,
);
index = index + faceCount * 3;
// Vertices
const vertices: number[] = [];
for (let i = 0; i < vertexCount; i++) {
const x = decodeFloat(encodedData[index++]);
const y = decodeFloat(encodedData[index++]);
const z = decodeFloat(encodedData[index++]);
vertices.push(x, y, z);
}
const vertices = new Float32Array(
encodedData.buffer,
index * 4,
vertexCount * 3,
);
// Add data to geometry
geometry.setIndex(indices);
geometry.setIndex([...indices]);
geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
// geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
geometry.computeVertexNormals();
return geometry;
}
@ -97,8 +96,6 @@
$: if (result) {
const inputs = parse_args(result);
console.log({ inputs });
for (let input of inputs) {
if (input[0] === 1) {
const geo = createGeometryFromEncodedData(input);

View File

@ -5,6 +5,24 @@
console.clear();
{
const encodedPositions = new Int32Array([
encodeFloat(1.1),
encodeFloat(2.0),
encodeFloat(3.0),
encodeFloat(4.0),
encodeFloat(5.0),
encodeFloat(6.0),
encodeFloat(7.0),
encodeFloat(8.0),
encodeFloat(9.0),
]);
// Create a Float32Array using the same buffer that backs the Int32Array
const floatView = new Float32Array(encodedPositions.buffer);
console.log({ encodedPositions, floatView });
}
if (false) {
const input_a = encode([1, 2, 3]);
const input_b = 2;
const input_c = 89;

View File

@ -1,6 +1,7 @@
use macros::include_definition_file;
use utils::{evaluate_args, get_args};
use wasm_bindgen::prelude::*;
use web_sys::console;
include_definition_file!("src/input.json");
@ -12,16 +13,19 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
let value_encoded = evaluate_args(args[0]);
// let value = decode_float(value_encoded[0], value_encoded[1]);
let length = args[1];
let length = (args[1][0]) as usize;
console::log_1(&format!("WASM(array): input: {:?} -> {:?}", args, value_encoded).into());
// construct array of length
let mut res: Vec<i32> = Vec::with_capacity(length[0] as usize * 2 + 2);
let mut res: Vec<i32> = Vec::with_capacity(length + 4);
res.push(0);
res.push((length[0]) * 2 + 2);
for _ in 0..length[0] as usize {
res.push(length as i32 + 4);
for _ in 0..length {
res.push(value_encoded[0]);
res.push(value_encoded[1])
}
res.push(1);
res.push(1);
res
}

6
nodes/max/plantarium/box/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
bin/
pkg/
wasm-pack.log

View File

@ -0,0 +1,28 @@
[package]
name = "box"
version = "0.1.0"
authors = ["Max Richter <jim-x@web.de>"]
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"

View File

@ -0,0 +1,6 @@
{
"scripts": {
"build": "wasm-pack build --release --out-name index --no-default-features",
"dev": "cargo watch -s 'pnpm build'"
}
}

View File

@ -0,0 +1,11 @@
{
"outputs": [
"model"
],
"inputs": {
"size": {
"type": "float",
"value": 2
}
}
}

View File

@ -0,0 +1,83 @@
use macros::include_definition_file;
use utils::{decode_float, encode_float, evaluate_args, get_args, set_panic_hook, wrap_arg};
use wasm_bindgen::prelude::*;
use web_sys::console;
include_definition_file!("src/input.json");
#[rustfmt::skip]
#[wasm_bindgen]
pub fn execute(input: &[i32]) -> Vec<i32> {
set_panic_hook();
let args = get_args(input);
console::log_1(&format!("WASM(cube): input: {:?} -> {:?}", input, args ).into());
let arg1 = evaluate_args(args[0]);
let decoded = decode_float(arg1[0]);
let p = encode_float(decoded);
let n = encode_float(-decoded);
// [[1,3, x, y, z, x, y,z,x,y,z]];
wrap_arg(&[
1, // 1: geometry
8, // 8 vertices
12, // 12 faces
/*
Indeces:
5----6
| 4--+-7
0-|--1 |
3----2
*/
// this are the indeces for the face
0, 1, 2,
0, 2, 3,
0, 3, 4,
4, 5, 0,
6, 1, 0,
5, 6, 0,
7, 2, 1,
6, 7, 1,
2, 7, 3,
3, 7, 4,
7, 6, 4,
4, 6, 5,
// this is the normal for every 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,
0, 1065353216, 0,
0, 1065353216, 0,
0, 1065353216, 0,
0, 1065353216, 0,
0, 1065353216, 0,
0, 1065353216, 0,
// Bottom plate
p, n, n,
p, n, p,
n, n, p,
n, n, n,
// Top Plate
n, p, n,
p, p, n,
p, p, p,
n, p, p,
])
}

View File

@ -0,0 +1,13 @@
//! 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);
}

View File

@ -5,12 +5,16 @@ include_definition_file!("src/input.json");
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(args.len() + 3);
let mut result = Vec::with_capacity(args.len() + 7);
result.push(0);
result.push(1);
result.push(0); // encoding the [ bracket
result.push(args[1] + 1);
result.push(0); // adding the node-type, math: 0
result.extend_from_slice(&args[2..]);
result.push(1);
result.push(1); // closing bracket
result.push(1);
result.push(1); // closing bracket
result
}

View File

@ -2,7 +2,10 @@
"outputs": [],
"inputs": {
"input": {
"type": "float",
"type": [
"plant",
"model"
],
"external": true
}
}

View File

@ -1,5 +1,5 @@
use macros::include_definition_file;
use utils::{decode_float, encode_float};
use utils::{concat_args, decode_float, encode_float, get_args};
use wasm_bindgen::prelude::*;
use web_sys::console;
@ -10,42 +10,27 @@ include_definition_file!("src/inputs.json");
pub fn execute(input: &[i32]) -> Vec<i32> {
utils::set_panic_hook();
let size = input[2];
let decoded = decode_float(input[2]);
let negative_size = encode_float(-decoded);
let args = get_args(input);
console::log_1(&format!("WASM(output_node): input: {:?} -> {}", input, decoded).into());
console::log_1(&format!("WASM(output_node): input: {:?}", args).into());
let mut output:Vec<&[i32]> = Vec::new();
for arg in args {
if arg.len() < 3 {
continue;
}
output.push( match arg[2] {
// stem
0 => &[0,1,1,1],
// geometry
1 => arg,
_ => &[0,1,1,1],
})
}
concat_args(output)
// [[1,3, x, y, z, x, y,z,x,y,z]];
vec![
0, 1, // opening bracket
0, 19, // opening bracket + distance to next bracket
1, // 1: geometry
3, // 3 vertices
1, // 1 face
// thise are the indeces for the face
0, 2, 1,
// this is the normal for the single face 1065353216 == 1.0f encoded is i32
0, 1065353216, 0,
//
negative_size, // x -> point 1
0, // y
0, // z
//
size, // x -> point 2
0, // y
0, // z
//
0, // x -> point 3
0, // y
size, // z
//
1, 1, 1, 1, // closing brackets
]
// let decoded = decode_float(result[0], result[1]);
// console::log_1(&format!("WASM: output: {:?}", decoded).into());
// result
}

View File

@ -22,7 +22,7 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
);
vec![
0, // opening bracket
0, 1, 0, // opening bracket
11, // opening bracket
0, // type: plant
0, // alpha: 0
@ -36,5 +36,7 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
1, // thickness
1, // closing bracket
1, //closing bracket
1, // closing bracket
1, //closing bracket
]
}

View File

@ -15,15 +15,13 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
let length = (input.len() - 2) / 2;
(0..length).for_each(|i| {
let mantissa = input[2 + i * 2];
let exponent = input[2 + i * 2 + 1];
// console::log_1(&format!("WASM(sum_node): i: {} sum: {:?}", i, sum).into());
sum += decode_float(mantissa, exponent);
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, 3, encoded_sum.0, encoded_sum.1]
vec![0, 2, encoded_sum]
}

View File

@ -18,9 +18,11 @@ wasm-bindgen = "0.2.84"
# 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"

View File

@ -0,0 +1,11 @@
{
"outputs": [
"model"
],
"inputs": {
"size": {
"type": "float",
"value": 2
}
}
}

View File

@ -1,24 +1,44 @@
use macros::include_definition_file;
use utils::{concat_args, decode_float, encode_float};
use wasm_bindgen::prelude::*;
use web_sys::console;
include_definition_file!("src/input.json");
#[rustfmt::skip]
#[wasm_bindgen]
pub fn get_outputs() -> Vec<String> {
vec!["float".to_string()]
}
pub fn execute(input: &[i32]) -> Vec<i32> {
#[wasm_bindgen]
pub fn get_input_types() -> String {
r#"{
"min": { "type": "float", "value": 2 },
"max": { "type": "float", "value": 2 },
"seed": { "type": "seed" }
}"#
.to_string()
}
let size = input[2];
let decoded = decode_float(input[2]);
let negative_size = encode_float(-decoded);
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {
// construct vertices of a triangle
// let min = evaluate_parameters(var_min);
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
1, // 1: geometry
3, // 3 vertices
1, // 1 face
// this are the indeces for the face
0, 2, 1,
// this is the normal for the single face 1065353216 == 1.0f encoded is i32
0, 1065353216, 0,
//
negative_size, // x -> point 1
0, // y
0, // z
//
size, // x -> point 2
0, // y
0, // z
//
0, // x -> point 3
0, // y
size, // z
//
1, 1 // closing brackets
]])
vec![1, 2, 3, 4, args[0]]
}

View File

@ -77,7 +77,7 @@ export interface RuntimeExecutor {
* @param graph - The graph to execute
* @returns The result of the execution
*/
execute: (graph: Graph) => void;
execute: (graph: Graph) => unknown;
}

View File

@ -36,7 +36,11 @@ type DefaultOptions = {
label?: string;
}
export type NodeInput = (NodeInputSeed | NodeInputBoolean | NodeInputFloat | NodeInputInteger | NodeInputSelect) & DefaultOptions;
type InputTypes = (NodeInputSeed | NodeInputBoolean | NodeInputFloat | NodeInputInteger | NodeInputSelect);
export type NodeInput = InputTypes & {
type: InputTypes["type"] | InputTypes["type"][];
} & DefaultOptions;
export type NodeInputType<T extends Record<string, NodeInput>> = {

View File

@ -57,6 +57,31 @@ pub fn get_args(args: &[i32]) -> Vec<&[i32]> {
out_args
}
pub fn concat_args(args: Vec<&[i32]>) -> Vec<i32> {
let total_length: usize = args.iter().map(|arg| arg.len()).sum();
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);
}
out_args.extend_from_slice(&[1, 1]);
out_args
}
pub fn wrap_arg(arg: &[i32]) -> Vec<i32> {
let mut out_args = Vec::with_capacity(arg.len() + 8);
out_args.extend_from_slice(&[0, 1, 0, arg.len() as i32 + 1]);
out_args.extend_from_slice(arg);
out_args.extend_from_slice(&[1, 1]);
out_args.extend_from_slice(&[1, 1]);
out_args
}
pub fn evaluate_node(input_args: &[i32]) -> i32 {
let node_type = input_args[0];
@ -67,6 +92,10 @@ pub fn evaluate_node(input_args: &[i32]) -> i32 {
}
pub fn evaluate_args(input_args: &[i32]) -> Vec<i32> {
if input_args.len() == 1 {
return input_args.to_vec();
}
if input_args.len() == 4 && input_args[0] == 0 && input_args[1] == 3 {
return vec![input_args[2], input_args[3]];
}
@ -82,14 +111,10 @@ pub fn evaluate_args(input_args: &[i32]) -> Vec<i32> {
resolved.push(arg[2]);
resolved.push(arg[3]);
} else {
let res = evaluate_args(arg);
resolved.push(res[0]);
resolved.push(res[1]);
resolved.push(evaluate_args(arg)[0]);
}
}
println!("resolved: {:?}", resolved);
if resolved.len() > 1 {
let res = evaluate_node(&resolved);
vec![res]