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;
}
const node: Node = { id: this.createNodeId(), type, position, tmp: { type: nodeType }, props };
this.nodes.update((nodes) => {

View File

@ -796,11 +796,19 @@
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);
graph.loadNode(nodeId).then(() => {
graph.createNode({
type: nodeId,
props: {},
props,
position: pos,
});
});

View File

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

View File

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

View File

@ -121,110 +121,80 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
const node_type = this.definitionMap.get(node.type)!;
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") {
inputs[key] = runSeed;
continue;
return runSeed;
}
if (input.setting) {
if (settings[input.setting] === undefined) {
if (input.value !== undefined) {
inputs[key] = input.value;
if ("value" in input && input.value !== undefined) {
if (input.type === "float") {
return encodeFloat(input.value);
}
return input.value;
} else {
log.warn(`Setting ${input.setting} is not defined`);
}
} 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
const inputNode = node.tmp.inputNodes?.[key];
const inputNode = node.tmp?.inputNodes?.[key];
if (inputNode) {
if (results[inputNode.id] === undefined) {
throw new Error("Input node has no result");
}
inputs[key] = results[inputNode.id];
continue;
return results[inputNode.id];
}
// if the input is not connected to another node, we use the value from the node itself
let value = node.props?.[key] ?? input?.value;
if (Array.isArray(value)) {
inputs[key] = [0, value.length + 1, ...value, 1, 1];
// If the value is stored in the node itself, we use that value
if (node.props?.[key] !== undefined) {
let value = node.props[key];
if (input.type === "vec3") {
return [0, 4, ...value.map(v => encodeFloat(v)), 1, 1]
} else if (Array.isArray(value)) {
return [0, value.length + 1, ...value, 1, 1];
} else if (input.type === "float") {
return encodeFloat(value);
} else {
inputs[key] = value;
}
}
// log.log(" ");
// log.log("--> EXECUTING NODE " + node_type.id, node.id);
// execute the node and store the result
try {
const a0 = performance.now();
const node_inputs = Object.entries(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;
}
}
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(transformed_inputs);
try {
const a2 = performance.now();
// log.log(`${a2 - a1}ms TRANSFORMED_INPUTS`);
const encoded_inputs = concatEncodedArrays(transformed_inputs);
const a3 = performance.now();
const encoded_inputs = concatEncodedArrays(inputs);
log.group(`executing ${node_type.id || node.id}`);
log.log(`Inputs:`, transformed_inputs);
log.log(`Inputs:`, inputs);
log.log(`Encoded Inputs:`, encoded_inputs);
results[node.id] = node_type.execute(encoded_inputs);
log.log("Result:", results[node.id]);
log.log("Result (decoded):", decodeNestedArray(results[node.id]));
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) {
log.groupEnd();
log.error(`Error executing node ${node_type.id || node.id}`, e);

View File

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

View File

@ -25,6 +25,7 @@
}
</script>
{#if store}
{#each keys as key}
{@const value = settings[key]}
<div class="wrapper" class:first-level={depth === 0}>
@ -34,13 +35,12 @@
<button on:click={() => settings[key]?.callback?.()}
>{settings[key].label || key}</button
>
{:else if "setting" in value}
<label for={key}>{settings[key].label || key}</label>
<Input id={key} input={value} bind:value={$store[value?.setting]} />
{:else}
<label for={key}>{settings[key].label || key}</label>
<Input
id={key}
input={value}
bind:value={$store[value?.setting || key]}
/>
<Input id={key} input={value} bind:value={$store[key]} />
{/if}
</div>
{:else}
@ -57,6 +57,7 @@
{/if}
</div>
{/each}
{/if}
<style>
summary {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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