| … | … | @@ -0,0 +1,12 @@ |
| 1 | extends SceneTree | |
| 2 | func _init() -> void: | |
| 3 | var a := OS.get_cmdline_user_args() | |
| 4 | var g: ProcNodeGraph = GraphImporter.import_from_json(FileAccess.get_file_as_string(a[0])) | |
| 5 | print("nodes=", g.get_node_count()) | |
| 6 | for sid in [37, 38, 39, 40, 41, 42, 99]: | |
| 7 | var idx: int = g.find_node_by_source_id(sid) | |
| 8 | var t := "-" | |
| 9 | if idx >= 0: | |
| 10 | t = str(g.get_node(idx).get_node_type()) | |
| 11 | print(" source id %2d -> index %2d %s" % [sid, idx, t]) | |
| 12 | quit() |
| … | … | @@ -905,6 +905,10 @@ Ref<ProcNodeGraph> GraphImporter::import_from_json(const String &p_json) { |
| 905 | 905 | _apply_defaults(node, defaults); |
| 906 | 906 | } |
| 907 | 907 | |
| 908 | // Keep the authoring id ON the node, not just in a local map that dies | |
| 909 | // with this function. A consumer holding an id -- blender-bridge's | |
| 910 | // parameter deltas do -- needs to reach the node afterwards. | |
| 911 | node->set_source_id(json_id); | |
| 908 | 912 | int graph_idx = graph->add_node(node); |
| 909 | 913 | id_to_idx[json_id] = graph_idx; |
| 910 | 914 | } |
| … | … | @@ -19,6 +19,8 @@ void ProcNode::_bind_methods() { |
| 19 | 19 | ClassDB::bind_method(D_METHOD("get_output_count"), &ProcNode::get_output_count); |
| 20 | 20 | ClassDB::bind_method(D_METHOD("get_graph_position"), &ProcNode::get_graph_position); |
| 21 | 21 | ClassDB::bind_method(D_METHOD("set_graph_position", "position"), &ProcNode::set_graph_position); |
| 22 | ClassDB::bind_method(D_METHOD("get_source_id"), &ProcNode::get_source_id); | |
| 23 | ClassDB::bind_method(D_METHOD("set_source_id", "id"), &ProcNode::set_source_id); | |
| 22 | 24 | ClassDB::bind_method(D_METHOD("get_input_default", "index"), &ProcNode::get_input_default); |
| 23 | 25 | ClassDB::bind_method(D_METHOD("get_input_name", "index"), &ProcNode::get_input_name); |
| 24 | 26 | ClassDB::bind_method(D_METHOD("get_input_type", "index"), &ProcNode::get_input_type); |
| … | … | @@ -28,6 +30,9 @@ void ProcNode::_bind_methods() { |
| 28 | 30 | ClassDB::bind_method(D_METHOD("is_input_default_modified", "index"), &ProcNode::is_input_default_modified); |
| 29 | 31 | |
| 30 | 32 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_position"), "set_graph_position", "get_graph_position"); |
| 33 | // Serialized, so a graph saved as a .tres can still be addressed by the ids | |
| 34 | // the tree it came from used. | |
| 35 | ADD_PROPERTY(PropertyInfo(Variant::INT, "source_id"), "set_source_id", "get_source_id"); | |
| 31 | 36 | } |
| 32 | 37 | |
| 33 | 38 | } // namespace godot |
| … | … | @@ -20,6 +20,17 @@ protected: |
| 20 | 20 | Vector<SocketDef> input_defs; |
| 21 | 21 | Vector<SocketDef> output_defs; |
| 22 | 22 | Vector2 graph_position; |
| 23 | ||
| 24 | // THE ID THE AUTHORING TOOL GAVE THIS NODE, -1 when it has none. | |
| 25 | // | |
| 26 | // GraphImporter builds a json-id -> graph-index map for connections and then | |
| 27 | // THREW IT AWAY, so a consumer holding an authoring id had no way to reach | |
| 28 | // the node. blender-bridge's parameter deltas carry exactly that id and were | |
| 29 | // passing it straight to get_node() as though it were an index -- which is | |
| 30 | // only correct while nothing is skipped. One unmapped node (SetMaterial) | |
| 31 | // shifts every index after it, so a delta wrote the WRONG node, and an id | |
| 32 | // past the end took the editor down with SIGSEGV. | |
| 33 | int source_id = -1; | |
| 23 | 34 | Vector<Variant> _constructor_defaults; // Captured lazily on first set_input_default |
| 24 | 35 | |
| 25 | 36 | void _capture_constructor_defaults() { |
| … | … | @@ -71,6 +82,8 @@ public: |
| 71 | 82 | // Graph editor position |
| 72 | 83 | Vector2 get_graph_position() const { return graph_position; } |
| 73 | 84 | void set_graph_position(const Vector2 &p_pos) { graph_position = p_pos; } |
| 85 | int get_source_id() const { return source_id; } | |
| 86 | void set_source_id(int p_id) { source_id = p_id; } | |
| 74 | 87 | |
| 75 | 88 | // Set default value for an input socket (used by GraphImporter and serialization) |
| 76 | 89 | void set_input_default(int p_idx, const Variant &p_value) { |
| … | … | @@ -128,6 +128,7 @@ void ProcNodeGraph::_bind_methods() { |
| 128 | 128 | ClassDB::bind_method(D_METHOD("evaluate_socket", "node_idx", "socket_idx"), &ProcNodeGraph::evaluate_socket); |
| 129 | 129 | ClassDB::bind_method(D_METHOD("evaluate_density_batch", "positions"), &ProcNodeGraph::evaluate_density_batch); |
| 130 | 130 | ClassDB::bind_method(D_METHOD("get_density_bounds"), &ProcNodeGraph::get_density_bounds); |
| 131 | ClassDB::bind_method(D_METHOD("find_node_by_source_id", "source_id"), &ProcNodeGraph::find_node_by_source_id); | |
| 131 | 132 | ClassDB::bind_method(D_METHOD("evaluate_density_at", "pos"), &ProcNodeGraph::evaluate_density_at); |
| 132 | 133 | ClassDB::bind_static_method("ProcNodeGraph", |
| 133 | 134 | D_METHOD("debug_phacelle_noise", "p", "dir", "freq", "offset", "normalization"), |
| … | … | @@ -568,6 +569,19 @@ bool ProcNodeGraph::find_density_output(int &r_node, int &r_socket) const { |
| 568 | 569 | return false; |
| 569 | 570 | } |
| 570 | 571 | |
| 572 | int ProcNodeGraph::find_node_by_source_id(int p_source_id) const { | |
| 573 | if (p_source_id < 0) { | |
| 574 | return -1; | |
| 575 | } | |
| 576 | for (int i = 0; i < get_node_count(); i++) { | |
| 577 | Ref<ProcNode> n = get_node(i); | |
| 578 | if (n.is_valid() && n->get_source_id() == p_source_id) { | |
| 579 | return i; | |
| 580 | } | |
| 581 | } | |
| 582 | return -1; | |
| 583 | } | |
| 584 | ||
| 571 | 585 | Dictionary ProcNodeGraph::get_density_bounds() const { |
| 572 | 586 | Dictionary out; |
| 573 | 587 | // The same terminal the density comes from: the graph's Group Output. Read |
| … | … | @@ -185,6 +185,11 @@ public: |
| 185 | 185 | // (hyper-games #65 NEXT 5). |
| 186 | 186 | bool find_density_output(int &r_node, int &r_socket) const; |
| 187 | 187 | |
| 188 | // The graph index of the node the authoring tool called p_source_id, or -1. | |
| 189 | // An id is NOT an index: the importer skips nodes it cannot map, so every | |
| 190 | // index after a skipped one is shifted. | |
| 191 | int find_node_by_source_id(int p_source_id) const; | |
| 192 | ||
| 188 | 193 | // THE GRAPH'S OWN EXTENT, declared beside its density. |
| 189 | 194 | // |
| 190 | 195 | // A Blender group interface takes any number of named, typed outputs, so a |