feat: load props from node store

This commit is contained in:
max_richter 2024-04-24 01:40:04 +02:00
parent f1e537d596
commit f0ccbf808e
13 changed files with 109 additions and 132 deletions

View File

@ -384,8 +384,6 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
return; return;
} }
const node: Node = { id: this.createNodeId(), type, position, tmp: { type: nodeType }, props }; const node: Node = { id: this.createNodeId(), type, position, tmp: { type: nodeType }, props };
this.nodes.update((nodes) => { this.nodes.update((nodes) => {

View File

@ -796,11 +796,19 @@
my += parseInt(nodeOffsetY); my += parseInt(nodeOffsetY);
} }
let props = {};
let rawNodeProps = event.dataTransfer.getData("data/node-props");
if (rawNodeProps) {
try {
props = JSON.parse(rawNodeProps);
} catch (e) {}
}
const pos = projectScreenToWorld(mx, my); const pos = projectScreenToWorld(mx, my);
graph.loadNode(nodeId).then(() => { graph.loadNode(nodeId).then(() => {
graph.createNode({ graph.createNode({
type: nodeId, type: nodeId,
props: {}, props,
position: pos, position: pos,
}); });
}); });

View File

@ -15,6 +15,7 @@ const diff = create({
}) })
const log = createLogger("history") const log = createLogger("history")
log.mute();
export class HistoryManager { export class HistoryManager {

View File

@ -6,12 +6,25 @@
let dragging = false; let dragging = false;
let nodeData = {
id: 0,
type: node.id,
position: [0, 0] as [number, number],
props: {},
tmp: {
type: node,
},
};
function handleDragStart(e: DragEvent) { function handleDragStart(e: DragEvent) {
dragging = true; dragging = true;
const box = (e?.target as HTMLElement)?.getBoundingClientRect(); const box = (e?.target as HTMLElement)?.getBoundingClientRect();
if (e.dataTransfer === null) return; if (e.dataTransfer === null) return;
e.dataTransfer.effectAllowed = "move"; e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("data/node-id", node.id); e.dataTransfer.setData("data/node-id", node.id);
if (nodeData.props) {
e.dataTransfer.setData("data/node-props", JSON.stringify(nodeData.props));
}
e.dataTransfer.setData( e.dataTransfer.setData(
"data/node-offset-x", "data/node-offset-x",
Math.round(box.left - e.clientX).toString(), Math.round(box.left - e.clientX).toString(),
@ -33,19 +46,7 @@
tabindex="0" tabindex="0"
on:dragstart={handleDragStart} on:dragstart={handleDragStart}
> >
<NodeHtml <NodeHtml inView={true} position={"relative"} z={5} bind:node={nodeData} />
inView={true}
position={"relative"}
z={5}
node={{
id: 0,
type: node.id,
position: [0, 0],
tmp: {
type: node,
},
}}
/>
</div> </div>
</div> </div>

View File

@ -121,110 +121,80 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
const node_type = this.definitionMap.get(node.type)!; const node_type = this.definitionMap.get(node.type)!;
if (node?.tmp && node_type?.execute) { if (node?.tmp && node_type?.execute) {
const inputs: Record<string, string | number | boolean> = {};
for (const [key, input] of Object.entries(node_type.inputs || {})) { const inputs = Object.entries(node_type.inputs || {}).map(([key, input]) => {
if (input.type === "seed") { if (input.type === "seed") {
inputs[key] = runSeed; return runSeed;
continue;
} }
if (input.setting) { if (input.setting) {
if (settings[input.setting] === undefined) { if (settings[input.setting] === undefined) {
if (input.value !== undefined) { if ("value" in input && input.value !== undefined) {
inputs[key] = input.value; if (input.type === "float") {
return encodeFloat(input.value);
}
return input.value;
} else { } else {
log.warn(`Setting ${input.setting} is not defined`); log.warn(`Setting ${input.setting} is not defined`);
} }
} else { } else {
inputs[key] = settings[input.setting] as number; if (input.type === "float") {
return encodeFloat(settings[input.setting] as number);
}
return settings[input.setting];
} }
continue;
} }
// check if the input is connected to another node // check if the input is connected to another node
const inputNode = node.tmp.inputNodes?.[key]; const inputNode = node.tmp?.inputNodes?.[key];
if (inputNode) { if (inputNode) {
if (results[inputNode.id] === undefined) { if (results[inputNode.id] === undefined) {
throw new Error("Input node has no result"); throw new Error("Input node has no result");
} }
inputs[key] = results[inputNode.id]; return results[inputNode.id];
continue;
} }
// if the input is not connected to another node, we use the value from the node itself // If the value is stored in the node itself, we use that value
let value = node.props?.[key] ?? input?.value; if (node.props?.[key] !== undefined) {
if (Array.isArray(value)) { let value = node.props[key];
inputs[key] = [0, value.length + 1, ...value, 1, 1]; if (input.type === "vec3") {
} else { return [0, 4, ...value.map(v => encodeFloat(v)), 1, 1]
inputs[key] = value; } else if (Array.isArray(value)) {
return [0, value.length + 1, ...value, 1, 1];
} else if (input.type === "float") {
return encodeFloat(value);
} else {
return value;
}
} }
} let defaultValue = input.value;
if (defaultValue !== undefined) {
if (Array.isArray(defaultValue)) {
return [0, defaultValue.length + 1, ...defaultValue.map(v => encodeFloat(v)), 1, 1];
} else if (input.type === "float") {
return encodeFloat(defaultValue);
} else {
return defaultValue;
}
}
throw new Error(`Input ${key} is not connected and has no default value`);
// log.log(" "); });
// log.log("--> EXECUTING NODE " + node_type.id, node.id);
// execute the node and store the result
try { try {
const a0 = performance.now();
const node_inputs = Object.entries(inputs); const encoded_inputs = concatEncodedArrays(inputs);
const cacheKey = "123" || `${node.id}/${fastHash(node_inputs.map(([_, value]: [string, any]) => {
return value
}))}`;
const a1 = performance.now();
// log.log(`${a1 - a0}ms hashed inputs: ${node.id} -> ${cacheKey}`);
if (false && this.cache[cacheKey] && this.cache[cacheKey].eol > Date.now()) {
results[node.id] = this.cache[cacheKey].value;
log.log(`Using cached value`);
continue;
}
const transformed_inputs = node_inputs.map(([key, value]: [string, any]) => {
const input_type = node_type.inputs?.[key]!;
if (value instanceof Int32Array) {
let _v = new Array(value.length);
for (let i = 0; i < value.length; i++) {
_v[i] = value[i];
}
return _v;
}
if (input_type.type === "float") {
return encodeFloat(value as number);
}
return value;
});
// log.log(transformed_inputs);
const a2 = performance.now();
// log.log(`${a2 - a1}ms TRANSFORMED_INPUTS`);
const encoded_inputs = concatEncodedArrays(transformed_inputs);
const a3 = performance.now();
log.group(`executing ${node_type.id || node.id}`); log.group(`executing ${node_type.id || node.id}`);
log.log(`Inputs:`, transformed_inputs); log.log(`Inputs:`, inputs);
log.log(`Encoded Inputs:`, encoded_inputs); log.log(`Encoded Inputs:`, encoded_inputs);
results[node.id] = node_type.execute(encoded_inputs); results[node.id] = node_type.execute(encoded_inputs);
log.log("Result:", results[node.id]); log.log("Result:", results[node.id]);
log.log("Result (decoded):", decodeNestedArray(results[node.id])); log.log("Result (decoded):", decodeNestedArray(results[node.id]));
log.groupEnd(); log.groupEnd();
const duration = performance.now() - a3;
if (duration > 5) {
this.cache[cacheKey] = { eol: Date.now() + 10_000, value: results[node.id] };
// log.log(`Caching for 10 seconds`);
}
// log.log(`${duration}ms Executed`);
const a4 = performance.now();
// log.log(`${a4 - a0}ms e2e duration`);
} catch (e) { } catch (e) {
log.groupEnd(); log.groupEnd();
log.error(`Error executing node ${node_type.id || node.id}`, e); log.error(`Error executing node ${node_type.id || node.id}`, e);

View File

@ -3,7 +3,6 @@
import NestedSettings from "./NestedSettings.svelte"; import NestedSettings from "./NestedSettings.svelte";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
import type { GraphManager } from "$lib/graph-interface/graph-manager"; import type { GraphManager } from "$lib/graph-interface/graph-manager";
import { encodeFloat } from "@nodes/utils";
function filterInputs(inputs: Record<string, NodeInput>) { function filterInputs(inputs: Record<string, NodeInput>) {
return Object.fromEntries( return Object.fromEntries(
@ -43,16 +42,11 @@
node.props = node.props || {}; node.props = node.props || {};
const key = _key as keyof typeof $store; const key = _key as keyof typeof $store;
if (node && $store) { if (node && $store) {
if (Array.isArray($store[key])) { needsUpdate = true;
node.props[key] = [...$store[key]].map((v) => encodeFloat(v)); node.props[key] = $store[key];
needsUpdate = true;
} else if (node.props[key] !== $store[key]) {
needsUpdate = true;
node.props[key] = $store[key];
}
} }
}); });
console.log(needsUpdate, node.props, $store); // console.log(needsUpdate, node.props, $store);
if (needsUpdate) { if (needsUpdate) {
manager.execute(); manager.execute();
} }

View File

@ -25,38 +25,39 @@
} }
</script> </script>
{#each keys as key} {#if store}
{@const value = settings[key]} {#each keys as key}
<div class="wrapper" class:first-level={depth === 0}> {@const value = settings[key]}
{#if isNodeInput(value)} <div class="wrapper" class:first-level={depth === 0}>
<div class="input input-{settings[key].type}"> {#if isNodeInput(value)}
{#if settings[key].type === "button"} <div class="input input-{settings[key].type}">
<button on:click={() => settings[key]?.callback?.()} {#if settings[key].type === "button"}
>{settings[key].label || key}</button <button on:click={() => settings[key]?.callback?.()}
> >{settings[key].label || key}</button
{:else} >
<label for={key}>{settings[key].label || key}</label> {:else if "setting" in value}
<Input <label for={key}>{settings[key].label || key}</label>
id={key} <Input id={key} input={value} bind:value={$store[value?.setting]} />
input={value} {:else}
bind:value={$store[value?.setting || key]} <label for={key}>{settings[key].label || key}</label>
/> <Input id={key} input={value} bind:value={$store[key]} />
{/if} {/if}
</div>
{:else}
{#if depth > 0}
<hr />
{/if}
<details bind:open={$expandedDetails[key]}>
<summary>{settings[key]?.__title || key}</summary>
<div class="content">
<svelte:self settings={settings[key]} {store} depth={depth + 1} />
</div> </div>
</details> {:else}
{/if} {#if depth > 0}
</div> <hr />
{/each} {/if}
<details bind:open={$expandedDetails[key]}>
<summary>{settings[key]?.__title || key}</summary>
<div class="content">
<svelte:self settings={settings[key]} {store} depth={depth + 1} />
</div>
</details>
{/if}
</div>
{/each}
{/if}
<style> <style>
summary { summary {

View File

@ -14,7 +14,11 @@
import NodeStore from "$lib/node-store/NodeStore.svelte"; import NodeStore from "$lib/node-store/NodeStore.svelte";
import type { GraphManager } from "$lib/graph-interface/graph-manager"; import type { GraphManager } from "$lib/graph-interface/graph-manager";
import { setContext } from "svelte"; import { setContext } from "svelte";
import { decodeNestedArray, encodeNestedArray } from "@nodes/utils"; import {
decodeFloat,
decodeNestedArray,
encodeNestedArray,
} from "@nodes/utils";
import type { PerspectiveCamera, Vector3 } from "three"; import type { PerspectiveCamera, Vector3 } from "three";
import type { OrbitControls } from "three/examples/jsm/Addons.js"; import type { OrbitControls } from "three/examples/jsm/Addons.js";
import ActiveNode from "$lib/settings/ActiveNode.svelte"; import ActiveNode from "$lib/settings/ActiveNode.svelte";
@ -24,6 +28,7 @@
globalThis.decode = decodeNestedArray; globalThis.decode = decodeNestedArray;
globalThis.encode = encodeNestedArray; globalThis.encode = encodeNestedArray;
globalThis.decodeFloat = decodeFloat;
let res: Int32Array; let res: Int32Array;
let viewerCamera: PerspectiveCamera; let viewerCamera: PerspectiveCamera;

View File

@ -21,6 +21,7 @@
"type": "float", "type": "float",
"label": "Fixate bottom of plant", "label": "Fixate bottom of plant",
"hidden": true, "hidden": true,
"value": 0,
"min": 0, "min": 0,
"max": 1 "max": 1
}, },

View File

@ -1,5 +1,4 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]

View File

@ -9,6 +9,7 @@
export let max: number | undefined = undefined; export let max: number | undefined = undefined;
export let step = 1; export let step = 1;
export let value = 0; export let value = 0;
export let id = "";
if (!value) { if (!value) {
value = 0; value = 0;

View File

@ -12,7 +12,7 @@ export function concatEncodedArrays(input: (number | number[])[]): number[] {
for (let i = 0; i < input.length; i++) { for (let i = 0; i < input.length; i++) {
const item = input[i]; const item = input[i];
if (Array.isArray(item)) { if (Array.isArray(item) || item instanceof Int32Array) {
result.push(...item); result.push(...item);
last_closing_bracket = result.length - 1; last_closing_bracket = result.length - 1;
} else { } else {

View File

@ -1,5 +1,3 @@
use crate::log;
use super::{create_geometry_data, wrap_geometry_data}; use super::{create_geometry_data, wrap_geometry_data};
use glam::{Mat4, Vec3}; use glam::{Mat4, Vec3};