feat: add vec3 to stem

This commit is contained in:
max_richter 2024-04-18 13:16:33 +02:00
parent 815152d23c
commit 32426ac045
31 changed files with 563 additions and 327 deletions

137
Cargo.lock generated
View File

@ -65,26 +65,6 @@ dependencies = [
"wasm-bindgen-test",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gl_matrix"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df64d0245c589931a0b5a385a63e7db2aeff209bdd471df0417e0f230a4c33ae"
dependencies = [
"rand",
]
[[package]]
name = "glam"
version = "0.27.0"
@ -106,12 +86,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "log"
version = "0.4.21"
@ -141,6 +115,48 @@ dependencies = [
"web-sys",
]
[[package]]
name = "max-plantarium-sum"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "max-plantarium-triangle"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "max-plantarium-vec3"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@ -152,6 +168,7 @@ name = "output"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"glam",
"macros",
"serde",
"serde-wasm-bindgen",
@ -162,12 +179,6 @@ dependencies = [
"web-sys",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.80"
@ -186,47 +197,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "random"
version = "0.1.0"
@ -308,20 +278,6 @@ dependencies = [
"web-sys",
]
[[package]]
name = "sum"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "syn"
version = "1.0.109"
@ -369,7 +325,6 @@ name = "utils"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"gl_matrix",
"glam",
"serde",
"serde_json",
@ -377,12 +332,6 @@ dependencies = [
"web-sys",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
version = "0.2.92"

View File

@ -6,13 +6,12 @@
export let node: Node;
export let input: NodeInput;
export let id: string;
export let label: string | undefined;
const graph = getGraphManager();
let value = node?.props?.[id] ?? input.value;
let elementId = Math.random().toString(36).substring(7);
export let elementId: string = `input-${Math.random().toString(36).substring(7)}`;
$: if (node?.props?.[id] !== value) {
node.props = { ...node.props, [id]: value };
@ -21,5 +20,4 @@
}
</script>
<label for="input-{elementId}">{label || id}</label>
<Input id="input-{elementId}" {input} bind:value />

View File

@ -1,174 +1,196 @@
<script lang="ts">
import type { NodeInput as NodeInputType, Socket, Node as NodeType } from '@nodes/types';
import { getContext } from 'svelte';
import { createNodePath } from '../helpers/index.js';
import { possibleSocketIds } from '../graph/stores.js';
import { getGraphManager } from '../graph/context.js';
import NodeInput from './NodeInput.svelte';
import type {
NodeInput as NodeInputType,
Socket,
Node as NodeType,
} from "@nodes/types";
import { getContext } from "svelte";
import { createNodePath } from "../helpers/index.js";
import { possibleSocketIds } from "../graph/stores.js";
import { getGraphManager } from "../graph/context.js";
import NodeInput from "./NodeInput.svelte";
export let node: NodeType;
export let input: NodeInputType;
export let id: string;
export let isLast = false;
export let node: NodeType;
export let input: NodeInputType;
export let id: string;
export let isLast = false;
const socketId = `${node.id}-${id}`;
const socketId = `${node.id}-${id}`;
const graph = getGraphManager();
const graphId = graph.id;
const inputSockets = graph.inputSockets;
const graph = getGraphManager();
const graphId = graph.id;
const inputSockets = graph.inputSockets;
const setDownSocket = getContext<(socket: Socket) => void>('setDownSocket');
const getSocketPosition =
getContext<(node: NodeType, index: string) => [number, number]>('getSocketPosition');
const elementId = `input-${Math.random().toString(36).substring(7)}`;
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
ev.stopPropagation();
setDownSocket({
node,
index: id,
position: getSocketPosition(node, id)
});
}
const setDownSocket = getContext<(socket: Socket) => void>("setDownSocket");
const getSocketPosition =
getContext<(node: NodeType, index: string) => [number, number]>(
"getSocketPosition",
);
const leftBump = node.tmp?.type?.inputs?.[id].internal !== true;
const cornerBottom = isLast ? 5 : 0;
const aspectRatio = 0.5;
function handleMouseDown(ev: MouseEvent) {
ev.preventDefault();
ev.stopPropagation();
setDownSocket({
node,
index: id,
position: getSocketPosition(node, id),
});
}
const path = createNodePath({
depth: 4,
height: 12,
y: 51,
cornerBottom,
leftBump,
aspectRatio
});
const pathDisabled = createNodePath({
depth: 0,
height: 15,
y: 50,
cornerBottom,
leftBump,
aspectRatio
});
const pathHover = createNodePath({
depth: 6,
height: 18,
y: 50.5,
cornerBottom,
leftBump,
aspectRatio
});
const leftBump = node.tmp?.type?.inputs?.[id].internal !== true;
const cornerBottom = isLast ? 5 : 0;
const aspectRatio = 0.5;
const path = createNodePath({
depth: 4,
height: 12,
y: 51,
cornerBottom,
leftBump,
aspectRatio,
});
const pathDisabled = createNodePath({
depth: 0,
height: 15,
y: 50,
cornerBottom,
leftBump,
aspectRatio,
});
const pathHover = createNodePath({
depth: 6,
height: 18,
y: 50.5,
cornerBottom,
leftBump,
aspectRatio,
});
</script>
<div class="wrapper" class:disabled={$possibleSocketIds && !$possibleSocketIds.has(socketId)}>
{#key id && graphId}
{#if node?.tmp?.type?.inputs?.[id]?.external !== true}
<div class="content" class:disabled={$inputSockets.has(socketId)}>
<NodeInput {node} {input} {id} label={input.label} />
</div>
{/if}
<div
class="wrapper"
class:disabled={$possibleSocketIds && !$possibleSocketIds.has(socketId)}
>
{#key id && graphId}
<div class="content" class:disabled={$inputSockets.has(socketId)}>
<label for={elementId}>{input.label || id}</label>
{#if node?.tmp?.type?.inputs?.[id]?.external !== true}
<NodeInput {elementId} {node} {input} {id} />
{/if}
</div>
{#if node?.tmp?.type?.inputs?.[id]?.internal !== true}
<div class="large target" on:mousedown={handleMouseDown} role="button" tabindex="0" />
<div class="small target" on:mousedown={handleMouseDown} role="button" tabindex="0" />
{/if}
{/key}
{#if node?.tmp?.type?.inputs?.[id]?.internal !== true}
<div
class="large target"
on:mousedown={handleMouseDown}
role="button"
tabindex="0"
/>
<div
class="small target"
on:mousedown={handleMouseDown}
role="button"
tabindex="0"
/>
{/if}
{/key}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
width="100"
height="100"
preserveAspectRatio="none"
style={`
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
width="100"
height="100"
preserveAspectRatio="none"
style={`
--path: path("${path}");
--hover-path: path("${pathHover}");
--hover-path-disabled: path("${pathDisabled}");
`}
>
<path vector-effect="non-scaling-stroke"></path>
</svg>
>
<path vector-effect="non-scaling-stroke"></path>
</svg>
</div>
<style>
.wrapper {
position: relative;
width: 100%;
height: 100px;
transform: translateY(-0.5px);
}
.wrapper {
position: relative;
width: 100%;
height: 100px;
transform: translateY(-0.5px);
}
.target {
position: absolute;
border-radius: 50%;
top: 50%;
transform: translateY(-50%) translateX(-50%);
/* background: red; */
/* opacity: 0.1; */
}
.target {
position: absolute;
border-radius: 50%;
top: 50%;
transform: translateY(-50%) translateX(-50%);
/* background: red; */
/* opacity: 0.1; */
}
.small.target {
width: 30px;
height: 30px;
}
.small.target {
width: 30px;
height: 30px;
}
.large.target {
width: 60px;
height: 60px;
cursor: unset;
pointer-events: none;
}
.large.target {
width: 60px;
height: 60px;
cursor: unset;
pointer-events: none;
}
:global(.hovering-sockets) .large.target {
pointer-events: all;
}
:global(.hovering-sockets) .large.target {
pointer-events: all;
}
.content {
position: relative;
padding: 10px 20px;
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-around;
box-sizing: border-box;
}
.content {
position: relative;
padding: 10px 20px;
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-around;
box-sizing: border-box;
}
:global(.zoom-small) .content {
display: none;
}
:global(.zoom-small) .content {
display: none;
}
svg {
position: absolute;
box-sizing: border-box;
width: 100%;
height: 100%;
overflow: visible;
top: 0;
left: 0;
z-index: -1;
}
svg {
position: absolute;
box-sizing: border-box;
width: 100%;
height: 100%;
overflow: visible;
top: 0;
left: 0;
z-index: -1;
}
svg path {
transition:
d 0.3s ease,
fill 0.3s ease;
fill: var(--background-color);
stroke: var(--stroke);
stroke-width: var(--stroke-width);
d: var(--path);
}
svg path {
transition:
d 0.3s ease,
fill 0.3s ease;
fill: var(--background-color);
stroke: var(--stroke);
stroke-width: var(--stroke-width);
d: var(--path);
}
:global(.hovering-sockets) .large:hover ~ svg path {
d: var(--hover-path);
}
:global(.hovering-sockets) .large:hover ~ svg path {
d: var(--hover-path);
}
.content.disabled {
opacity: 0.2;
pointer-events: none;
}
.content.disabled {
opacity: 0.2;
pointer-events: none;
}
.disabled svg path {
d: var(--hover-path-disabled) !important;
}
.disabled svg path {
d: var(--hover-path-disabled) !important;
}
</style>

View File

@ -73,6 +73,7 @@ export class RemoteNodeRegistry implements NodeRegistry {
nodeIds.push("max/plantarium/random");
nodeIds.push("max/plantarium/float");
nodeIds.push("max/plantarium/triangle");
nodeIds.push("max/plantarium/vec3");
nodeIds.push("max/plantarium/output");
nodeIds.push("max/plantarium/array");
nodeIds.push("max/plantarium/sum");

View File

@ -1,5 +1,5 @@
import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "@nodes/types";
import { fastHash, concat_encoded, encodeFloat } from "@nodes/utils"
import { fastHash, concat_encoded, encodeFloat, encode } from "@nodes/utils"
export class MemoryRuntimeExecutor implements RuntimeExecutor {
@ -176,15 +176,22 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
return encodeFloat(value as number);
}
if (Array.isArray(value)) {
return encode(value);
}
return value;
});
console.log(transformed_inputs);
const a2 = performance.now();
// console.log(`${a2 - a1}ms TRANSFORMED_INPUTS`);
const _inputs = concat_encoded(transformed_inputs);
const a3 = performance.now();
console.log(`executing ${node_type.id || node.id}`, _inputs);
results[node.id] = node_type.execute(_inputs) as number;
const duration = performance.now() - a3;
if (duration > 5) {

View File

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

View File

@ -0,0 +1,28 @@
[package]
name = "triangle"
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,4 @@
{
"outputs": [],
"inputs": {}
}

View File

@ -0,0 +1,12 @@
use macros::include_definition_file;
use utils::{decode_float, encode_float, 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> {
vec![]
}

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

@ -1,5 +1,5 @@
use macros::include_definition_file;
use utils::{evaluate_args, get_args};
use utils::{evaluate_arg, get_args};
use wasm_bindgen::prelude::*;
use web_sys::console;
@ -11,9 +11,8 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
let args = get_args(input);
let value_encoded = evaluate_args(args[0]);
// let value = decode_float(value_encoded[0], value_encoded[1]);
let length = (args[1][0]) as usize;
let value_encoded = evaluate_arg(args[0]);
let length = evaluate_arg(args[1]) as usize;
console::log_1(&format!("WASM(array): input: {:?} -> {:?}", args, value_encoded).into());
@ -22,7 +21,7 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
res.push(0);
res.push(length as i32 + 4);
for _ in 0..length {
res.push(value_encoded[0]);
res.push(value_encoded);
}
res.push(1);
res.push(1);

View File

@ -1,7 +1,6 @@
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,
encode_float, evaluate_float, geometry::calculate_normals, get_args, set_panic_hook, wrap_arg,
};
use wasm_bindgen::prelude::*;
use web_sys::console;
@ -18,12 +17,10 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
console::log_1(&format!("WASM(cube): input: {:?} -> {:?}", input, args ).into());
let arg1 = evaluate_args(args[0]);
let size = evaluate_float(args[0]);
let decoded = decode_float(arg1[0]);
let p = encode_float(decoded);
let n = encode_float(-decoded);
let p = encode_float(size);
let n = encode_float(-size);
// [[1,3, x, y, z, x, y,z,x,y,z]];

View File

@ -25,6 +25,7 @@ macros = { version = "0.1.0", path = "../../../../packages/macros" }
serde-wasm-bindgen = "0.4"
console_error_panic_hook = { version = "0.1.7", optional = true }
web-sys = { version = "0.3.69", features = ["console"] }
glam = "0.27.0"
[dev-dependencies]
wasm-bindgen-test = "0.3.34"

View File

@ -1,31 +1,36 @@
use glam::{Mat4, Vec3};
use macros::include_definition_file;
use utils::{concat_args, geometry::extrude_path, get_args};
use utils::{
concat_args,
geometry::{extrude_path, transform_geometry},
get_args,
};
use wasm_bindgen::prelude::*;
include_definition_file!("src/inputs.json");
#[rustfmt::skip]
#[wasm_bindgen]
pub fn execute(input: Vec<i32>) -> Vec<i32> {
utils::set_panic_hook();
let args = get_args(input.as_slice());
let mut output:Vec<Vec<i32>> = Vec::new();
let mut output: Vec<Vec<i32>> = 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, 16);
let mut geometry = extrude_path(_arg, 4);
let matrix = Mat4::from_translation(Vec3::new(0.0, 0.0, 0.0));
geometry = transform_geometry(geometry, matrix);
output.push(geometry);
}else if arg[2] == 1 {
} else if arg[2] == 1 {
output.push(arg.to_vec());
}
}
concat_args(output)
}

View File

@ -3,6 +3,15 @@
"plant"
],
"inputs": {
"origin": {
"type": "vec3",
"value": [
0,
0,
0
],
"external": true
},
"length": {
"type": "float",
"value": 2

View File

@ -1,5 +1,5 @@
use macros::include_definition_file;
use utils::{decode_float, evaluate_args, get_args, set_panic_hook, wrap_arg};
use utils::{evaluate_float, evaluate_vec3, get_args, log, set_panic_hook, wrap_arg};
use wasm_bindgen::prelude::*;
include_definition_file!("src/input.json");
@ -10,9 +10,13 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
let args = get_args(input);
let length = decode_float(evaluate_args(args[0])[0]);
let thickness = decode_float(evaluate_args(args[1])[0]);
let resolution = 512; //evaluate_args(args[2]);
log!("Args: {:?}", args);
let origin = evaluate_vec3(args[0]);
log!("Origin: {:?}", origin);
let length = evaluate_float(args[1]);
let thickness = evaluate_float(args[2]);
let resolution = 16;
let mut path: Vec<i32> = vec![0; resolution * 4 + 1];
path.resize(resolution * 4 + 1, 0);
@ -32,9 +36,9 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
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] = origin[0] + (a * 8.0).sin() * 0.2;
path_p[i * 4 + 1] = origin[1] + a * length;
path_p[i * 4 + 2] = origin[2] + 0.0;
path_p[i * 4 + 3] = thickness * (1.0 - a);
}

View File

@ -1,5 +1,5 @@
[package]
name = "sum"
name = "max-plantarium-sum"
version = "0.1.0"
authors = ["Max Richter <jim-x@web.de>"]
edition = "2018"

View File

@ -1,5 +1,5 @@
[package]
name = "triangle"
name = "max-plantarium-triangle"
version = "0.1.0"
authors = ["Max Richter <jim-x@web.de>"]
edition = "2018"

6
nodes/max/plantarium/vec3/.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 = "max-plantarium-vec3"
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,16 @@
{
"outputs": [
"vec3"
],
"inputs": {
"0": {
"type": "float"
},
"1": {
"type": "float"
},
"2": {
"type": "float"
}
}
}

View File

@ -0,0 +1,20 @@
use macros::include_definition_file;
use utils::log;
use wasm_bindgen::prelude::*;
include_definition_file!("src/input.json");
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(args.len() + 2);
result.push(0); // encoding the [ bracket
result.push(args[1]);
result.extend_from_slice(&args[2..]);
result.push(1);
result.push(1); // closing bracket
log!("WASM(vec3): res {:?}", result);
result
}

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

@ -12,5 +12,4 @@ 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 }
gl_matrix = "0.0.2"
glam = "0.27.0"

View File

@ -1,4 +1,4 @@
use super::create_empty_geometry;
use super::{create_geometry_data, wrap_geometry_data};
use glam::{Mat4, Quat, Vec3};
fn create_circle(res: usize) -> Vec<f32> {
@ -19,22 +19,19 @@ pub fn extrude_path(input_path: &[i32], res_x: usize) -> Vec<i32> {
let circle = create_circle(res_x);
let mut geometry = create_empty_geometry(vertices_amount, face_amount);
let mut geometry_data = create_geometry_data(vertices_amount, face_amount);
let geometry = wrap_geometry_data(&mut geometry_data);
let normals = geometry.normals;
let positions = geometry.positions;
let indices = geometry.faces;
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;
@ -109,5 +106,5 @@ pub fn extrude_path(input_path: &[i32], res_x: usize) -> Vec<i32> {
}
}
geometry
geometry_data
}

View File

@ -0,0 +1,74 @@
use crate::log;
pub struct GeometryData<'a> {
pub positions: &'a mut [f32], // View into `data`
pub normals: &'a mut [f32], // View into `data`
pub faces: &'a mut [i32], // View into `data`
}
pub fn create_geometry_data(vertex_amount: usize, face_amount: usize) -> Vec<i32> {
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 geo = vec![0; amount];
geo[0] = 0; // opening bracket
geo[1] = amount as i32 - 2; // opening bracket
geo[2] = 1; // type: geometry
geo[3] = vertex_amount as i32;
geo[4] = face_amount as i32;
geo[amount - 2] = 1; // closing bracket
geo[amount - 1] = 1; // closing bracket
geo
}
pub fn wrap_geometry_data(geometry: &mut [i32]) -> GeometryData {
// Basic validity checks
assert!(
geometry.len() > 5,
"Geometry vector does not contain enough data for a header."
);
// Split at after header
let (header, rest) = geometry.split_at_mut(5);
let vertices_amount = header[3] as usize;
let face_amount = header[4] as usize;
let total_floats = vertices_amount * 3 * 2;
let (faces, rest) = rest.split_at_mut(face_amount * 3);
let (positions_slice, rest) = rest.split_at_mut(vertices_amount * 3);
let (normals_slice, _) = rest.split_at_mut(vertices_amount * 3);
log!(
"Vertices: {}, normals: {}, Total floats: {}",
positions_slice.len(),
normals_slice.len(),
total_floats
);
assert!(
positions_slice.len() + normals_slice.len() == total_floats,
"Slices do not match the expected sizes."
);
let positions: &mut [f32] = unsafe {
std::slice::from_raw_parts_mut(
positions_slice.as_mut_ptr() as *mut f32,
positions_slice.len(),
)
};
let normals: &mut [f32] = unsafe {
std::slice::from_raw_parts_mut(normals_slice.as_mut_ptr() as *mut f32, normals_slice.len())
};
GeometryData {
positions,
normals,
faces,
}
}

View File

@ -1,33 +1,9 @@
mod calculate_normals;
mod extrude_path;
mod geometry;
mod transform;
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<i32> {
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<i32> = 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
}
pub use geometry::*;
pub use transform::*;

View File

@ -0,0 +1,25 @@
use glam::{Mat4, Vec3};
pub fn transform_geometry(mut geometry: Vec<i32>, matrix: Mat4) -> Vec<i32> {
let (_header, rest) = geometry.split_at_mut(5);
let vertices_amount = _header[3] as usize;
let face_amount = _header[4] as usize;
let (_indices, rest) = rest.split_at_mut(face_amount * 3);
let (_positions, _normals) = rest.split_at_mut(vertices_amount * 3);
let positions: &mut [f32];
unsafe {
positions =
std::slice::from_raw_parts_mut(_positions.as_mut_ptr() as *mut f32, _positions.len());
}
for i in 0..vertices_amount {
let pos = Mat4::transform_point3(&matrix, Vec3::from_slice(&positions[i * 3..i * 3 + 3]));
positions[i * 3] = pos.x;
positions[i * 3 + 1] = pos.y;
positions[i * 3 + 2] = pos.z;
}
geometry
}

View File

@ -1,3 +1,5 @@
use crate::decode_float;
pub fn get_args(args: &[i32]) -> Vec<&[i32]> {
let mut idx: usize = 0;
let mut depth = -1;
@ -105,13 +107,29 @@ 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();
}
pub fn evaluate_vec3(input_args: &[i32]) -> Vec<f32> {
let args = get_args(input_args);
if input_args.len() == 4 && input_args[0] == 0 && input_args[1] == 3 {
return vec![input_args[2], input_args[3]];
assert!(
args.len() == 3,
"Failed to evaluate Vec3 - Expected 3 arguments, got {}",
args.len()
);
let x = evaluate_float(args[0]);
let y = evaluate_float(args[1]);
let z = evaluate_float(args[2]);
vec![x, y, z]
}
pub fn evaluate_float(arg: &[i32]) -> f32 {
decode_float(evaluate_arg(arg))
}
pub fn evaluate_arg(input_args: &[i32]) -> i32 {
if input_args.len() == 1 {
return input_args.to_vec()[0];
}
let args = get_args(input_args);
@ -125,22 +143,20 @@ pub fn evaluate_args(input_args: &[i32]) -> Vec<i32> {
resolved.push(arg[2]);
resolved.push(arg[3]);
} else {
resolved.push(evaluate_args(arg)[0]);
resolved.push(evaluate_arg(arg));
}
}
if resolved.len() > 1 {
let res = evaluate_node(&resolved);
vec![res]
evaluate_node(&resolved)
} else {
resolved
resolved[0]
}
}
#[cfg(test)]
mod tests {
use crate::encoding::decode_float;
use super::*;
#[test]
@ -152,10 +168,9 @@ mod tests {
// and another math node that adds 2 to that result
// the numbers are f32 floats encoded as two i32's
let result = evaluate_args(&input);
let decoded = decode_float(result[0]);
let result = evaluate_float(&input);
assert_eq!(decoded, 6.0);
assert_eq!(result, 6.0);
}
#[test]