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(); }