224 lines
7.5 KiB
JavaScript
224 lines
7.5 KiB
JavaScript
import { Node, ServoNode, VariableNode, CurveNode, MathNode, MapNode, NoiseNode } from './Node.js';
|
|
|
|
export const NODE_TYPES = {
|
|
Node: 0x01,
|
|
Servo: 0x02,
|
|
Curve: 0x03,
|
|
Noise: 0x04,
|
|
Variable: 0x05,
|
|
Math: 0x06,
|
|
Map: 0x07
|
|
};
|
|
|
|
function GetNodeType(node) {
|
|
console.log(node.constructor.name);
|
|
switch (node.constructor.name) {
|
|
case "ServoNode":
|
|
return NODE_TYPES.Servo;
|
|
case "CurveNode":
|
|
return NODE_TYPES.Curve;
|
|
case "NoiseNode":
|
|
return NODE_TYPES.Noise;
|
|
case "VariableNode":
|
|
return NODE_TYPES.Variable;
|
|
case "MathNode":
|
|
return NODE_TYPES.Math;
|
|
case "MapNode":
|
|
return NODE_TYPES.Map;
|
|
default:
|
|
return NODE_TYPES.Node;
|
|
}
|
|
}
|
|
|
|
export function encodeNodeGraph(nodes, connections) {
|
|
const bufferSize = 1024; // adjust based on expected graph size
|
|
const buffer = new ArrayBuffer(bufferSize);
|
|
const view = new DataView(buffer);
|
|
let offset = 0;
|
|
|
|
|
|
// Node count (1 byte)
|
|
view.setUint8(offset++, nodes.length);
|
|
//console.log(ndoes);
|
|
// Encode nodes
|
|
nodes.forEach((node, index) => {
|
|
node.id = index;
|
|
node.type = GetNodeType(node);
|
|
|
|
view.setUint8(offset++, node.type); // Node type
|
|
view.setUint8(offset++, node.id); // Node ID
|
|
view.setUint16(offset, node.x, true); offset += 2;
|
|
view.setUint16(offset, node.y, true); offset += 2;
|
|
|
|
|
|
switch (node.type) {
|
|
case NODE_TYPES.Servo:
|
|
view.setUint8(offset++, node.controls[0].getValue());
|
|
break;
|
|
|
|
case NODE_TYPES.Curve:
|
|
view.setUint8(offset++, node.controls[0].getValue());
|
|
break;
|
|
|
|
case NODE_TYPES.Noise:
|
|
view.setFloat32(offset, node.controls[0].getValue(), true); offset += 4;
|
|
view.setUint16(offset, node.controls[1].getValue()); offset += 2;
|
|
break;
|
|
|
|
|
|
case NODE_TYPES.Variable:
|
|
view.setUint8(offset++, node.controls[0].getValue());
|
|
view.setUint8(offset++, node.controls[1].getValue());
|
|
break;
|
|
|
|
|
|
case NODE_TYPES.Math:
|
|
view.setUint8(offset++, node.controls[0].getValue());
|
|
view.setFloat32(offset, node.controls[1].getValue(), true); offset += 4;
|
|
break;
|
|
|
|
case NODE_TYPES.Map:
|
|
view.setFloat32(offset, node.controls[0].getValue(), true); offset += 4;
|
|
view.setFloat32(offset, node.controls[1].getValue(), true); offset += 4;
|
|
view.setFloat32(offset, node.controls[2].getValue(), true); offset += 4;
|
|
view.setFloat32(offset, node.controls[3].getValue(), true); offset += 4;
|
|
//console.log(node.inMinInput.numericValue, node.inMaxInput.numericValue, node.outMinInput.numericValue, node.outMaxInput.numericValue);
|
|
break;
|
|
|
|
default:
|
|
console.warn("Unknown node type:", node);
|
|
}
|
|
});
|
|
|
|
// Connection count (1 byte)
|
|
view.setUint8(offset++, connections.length);
|
|
|
|
// Encode connections
|
|
connections.forEach(conn => {
|
|
view.setUint8(offset++, conn.from.id);
|
|
view.setUint8(offset++, conn.to.id);
|
|
});
|
|
|
|
// Slice the buffer to actual used size
|
|
return new Uint8Array(buffer.slice(0, offset));
|
|
}
|
|
|
|
export function loadFromBinary(editor, data) {
|
|
let nodes = []
|
|
let connections = []
|
|
const view = new DataView(data.buffer);
|
|
let offset = 0;
|
|
|
|
const nodeCount = view.getUint8(offset++);
|
|
const idMap = {}; // Map node IDs to actual node instances
|
|
|
|
for (let i = 0; i < nodeCount; i++) {
|
|
const type = view.getUint8(offset++);
|
|
const id = view.getUint8(offset++);
|
|
const x = view.getUint16(offset, true); offset += 2;
|
|
const y = view.getUint16(offset, true); offset += 2;
|
|
|
|
let node = null;
|
|
|
|
switch (type) {
|
|
case NODE_TYPES.Servo: {
|
|
const motorID = view.getUint8(offset++);
|
|
const newNode = new ServoNode(x, y, motorID);
|
|
editor.nodes.push(newNode);
|
|
node = newNode;
|
|
break;
|
|
}
|
|
case NODE_TYPES.Curve: {
|
|
const curveID = view.getUint8(offset++);
|
|
const newNode = new CurveNode(x, y, curveID);
|
|
editor.nodes.push(newNode);
|
|
node = newNode;
|
|
break;
|
|
}
|
|
case NODE_TYPES.Noise: {
|
|
const frequency = view.getFloat32(offset, true); offset += 4;
|
|
const seed = view.getUint16(offset, true); offset += 2;
|
|
const newNode = new NoiseNode(x, y);
|
|
editor.nodes.push(newNode);
|
|
node = newNode;
|
|
node.controls[0].text = String(frequency);
|
|
node.controls[1].text = String(seed);
|
|
break;
|
|
}
|
|
case NODE_TYPES.Variable: {
|
|
const source = view.getUint8(offset++);
|
|
const arg0 = view.getUint8(offset++);
|
|
const newNode = new VariableNode(x, y);
|
|
editor.nodes.push(newNode);
|
|
node = newNode;
|
|
node.controls[0].selectedIndex = source;
|
|
node.controls[1].value = arg0;
|
|
break;
|
|
}
|
|
case NODE_TYPES.Math: {
|
|
const op = view.getUint8(offset++);
|
|
const value = view.getFloat32(offset, true); offset += 4;
|
|
const newNode = new MathNode(x, y);
|
|
editor.nodes.push(newNode);
|
|
node = newNode;
|
|
node.controls[0].selectedIndex = op;
|
|
node.controls[1].text = String(value);
|
|
break;
|
|
}
|
|
case NODE_TYPES.Map: {
|
|
const inMin = view.getFloat32(offset, true); offset += 4;
|
|
const inMax = view.getFloat32(offset, true); offset += 4;
|
|
const outMin = view.getFloat32(offset, true); offset += 4;
|
|
const outMax = view.getFloat32(offset, true); offset += 4;
|
|
const newNode = new MapNode(x, y);
|
|
editor.nodes.push(newNode);
|
|
node = newNode;
|
|
node.controls[0].text = String(inMin);
|
|
node.controls[1].text = String(inMax);
|
|
node.controls[2].text = String(outMin);
|
|
node.controls[3].text = String(outMax);
|
|
break;
|
|
}
|
|
default: {
|
|
console.error("UNKNOWN NODE");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (node) {
|
|
node.id = id;
|
|
idMap[id] = node;
|
|
}
|
|
//editor.nodes.push(node);
|
|
}
|
|
|
|
//console.log(this.getNodeByID(0));
|
|
|
|
// 🔗 Load connections
|
|
const connectionCount = view.getUint8(offset++);
|
|
for (let i = 0; i < connectionCount; i++) {
|
|
const fromID = view.getUint8(offset++);
|
|
const toID = view.getUint8(offset++);
|
|
const fromNode = idMap[fromID];
|
|
const toNode = idMap[toID];
|
|
if (fromNode && toNode) {
|
|
editor.connections.push({ from: fromNode, to: toNode });
|
|
}
|
|
}
|
|
|
|
|
|
// Reencode all positions to SIGNED ints
|
|
editor.nodes.forEach(node => {
|
|
node.x = (node.x << 16) >> 16;
|
|
node.y = (node.y << 16) >> 16;
|
|
});
|
|
|
|
|
|
//editor.nodes = nodes;
|
|
//editor.connections = connections;
|
|
console.log(editor.nodes);
|
|
console.log(editor.connections);
|
|
editor.draw();
|
|
//this._redraw();
|
|
} |