Added preview nodes (has a few limitations, may fix them later)
This commit is contained in:
parent
4ff29ce3ce
commit
b8c235fce3
@ -1,6 +1,9 @@
|
||||
#include "voxel_graph_editor.h"
|
||||
#include "../generators/graph/voxel_generator_graph.h"
|
||||
#include "editor/editor_scale.h"
|
||||
|
||||
#include <core/core_string_names.h>
|
||||
#include <core/os/os.h>
|
||||
#include <core/undo_redo.h>
|
||||
#include <scene/gui/graph_edit.h>
|
||||
#include <scene/gui/label.h>
|
||||
@ -8,11 +11,44 @@
|
||||
const char *VoxelGraphEditor::SIGNAL_NODE_SELECTED = "node_selected";
|
||||
const char *VoxelGraphEditor::SIGNAL_NOTHING_SELECTED = "nothing_selected";
|
||||
|
||||
// Shows a 2D slice of the 3D set of values coming from an output port
|
||||
class VoxelGraphEditorNodePreview : public VBoxContainer {
|
||||
GDCLASS(VoxelGraphEditorNodePreview, VBoxContainer)
|
||||
public:
|
||||
static const int RESOLUTION = 64;
|
||||
|
||||
VoxelGraphEditorNodePreview() {
|
||||
_image.instance();
|
||||
_image->create(RESOLUTION, RESOLUTION, false, Image::FORMAT_L8);
|
||||
_texture.instance();
|
||||
update_texture();
|
||||
_texture_rect = memnew(TextureRect);
|
||||
_texture_rect->set_stretch_mode(TextureRect::STRETCH_SCALE);
|
||||
_texture_rect->set_custom_minimum_size(Vector2(RESOLUTION, RESOLUTION));
|
||||
_texture_rect->set_texture(_texture);
|
||||
add_child(_texture_rect);
|
||||
}
|
||||
|
||||
Ref<Image> get_image() const {
|
||||
return _image;
|
||||
}
|
||||
|
||||
void update_texture() {
|
||||
_texture->create_from_image(_image, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
TextureRect *_texture_rect = nullptr;
|
||||
Ref<ImageTexture> _texture;
|
||||
Ref<Image> _image;
|
||||
};
|
||||
|
||||
// Graph node with a few custom data attached.
|
||||
class VoxelGraphEditorNode : public GraphNode {
|
||||
GDCLASS(VoxelGraphEditorNode, GraphNode)
|
||||
public:
|
||||
uint32_t node_id = 0;
|
||||
VoxelGraphEditorNodePreview *preview = nullptr;
|
||||
};
|
||||
|
||||
VoxelGraphEditor::VoxelGraphEditor() {
|
||||
@ -43,13 +79,15 @@ void VoxelGraphEditor::set_graph(Ref<VoxelGeneratorGraph> graph) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (_graph.is_valid()) {
|
||||
// }
|
||||
if (_graph.is_valid()) {
|
||||
_graph->disconnect(CoreStringNames::get_singleton()->changed, this, "_on_graph_changed");
|
||||
}
|
||||
|
||||
_graph = graph;
|
||||
|
||||
// if (_graph.is_valid()) {
|
||||
// }
|
||||
if (_graph.is_valid()) {
|
||||
_graph->connect(CoreStringNames::get_singleton()->changed, this, "_on_graph_changed");
|
||||
}
|
||||
|
||||
build_gui_from_graph();
|
||||
}
|
||||
@ -58,6 +96,27 @@ void VoxelGraphEditor::set_undo_redo(UndoRedo *undo_redo) {
|
||||
_undo_redo = undo_redo;
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_INTERNAL_PROCESS:
|
||||
_process(get_tree()->get_idle_process_time());
|
||||
break;
|
||||
|
||||
case NOTIFICATION_VISIBILITY_CHANGED:
|
||||
set_process_internal(is_visible());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::_process(float delta) {
|
||||
if (_time_before_preview_update > 0.f) {
|
||||
_time_before_preview_update -= delta;
|
||||
if (_time_before_preview_update < 0.f) {
|
||||
update_previews();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::clear() {
|
||||
_graph_edit->clear_connections();
|
||||
for (int i = 0; i < _graph_edit->get_child_count(); ++i) {
|
||||
@ -164,6 +223,11 @@ void VoxelGraphEditor::create_node_gui(uint32_t node_id) {
|
||||
node_view->set_slot(i, has_left, Variant::REAL, port_color, has_right, Variant::REAL, port_color);
|
||||
}
|
||||
|
||||
if (node_type_id == VoxelGeneratorGraph::NODE_SDF_PREVIEW) {
|
||||
node_view->preview = memnew(VoxelGraphEditorNodePreview);
|
||||
node_view->add_child(node_view->preview);
|
||||
}
|
||||
|
||||
_graph_edit->add_child(node_view);
|
||||
}
|
||||
|
||||
@ -386,6 +450,89 @@ void VoxelGraphEditor::_check_nothing_selected() {
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::update_previews() {
|
||||
if (_graph.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t time_before = OS::get_singleton()->get_ticks_usec();
|
||||
|
||||
_graph->compile();
|
||||
|
||||
// TODO Use a thread?
|
||||
print_line("Updating previews");
|
||||
|
||||
struct PreviewInfo {
|
||||
VoxelGraphEditorNodePreview *control;
|
||||
uint16_t address;
|
||||
float min_value;
|
||||
float value_scale;
|
||||
};
|
||||
|
||||
std::vector<PreviewInfo> previews;
|
||||
const VoxelGraphRuntime &runtime = _graph->get_runtime();
|
||||
|
||||
for (int i = 0; i < _graph_edit->get_child_count(); ++i) {
|
||||
VoxelGraphEditorNode *node = Object::cast_to<VoxelGraphEditorNode>(_graph_edit->get_child(i));
|
||||
if (node == nullptr || node->preview == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ProgramGraph::PortLocation dst;
|
||||
dst.node_id = node->node_id;
|
||||
dst.port_index = 0;
|
||||
ProgramGraph::PortLocation src;
|
||||
if (!_graph->try_get_connection_to(dst, src)) {
|
||||
// Not connected?
|
||||
continue;
|
||||
}
|
||||
PreviewInfo info;
|
||||
info.control = node->preview;
|
||||
info.address = runtime.get_output_port_address(src);
|
||||
info.min_value = _graph->get_node_param(dst.node_id, 0);
|
||||
const float max_value = _graph->get_node_param(dst.node_id, 1);
|
||||
info.value_scale = 1.f / (max_value - info.min_value);
|
||||
previews.push_back(info);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < previews.size(); ++i) {
|
||||
previews[i].control->get_image()->lock();
|
||||
}
|
||||
|
||||
for (int iy = 0; iy < VoxelGraphEditorNodePreview::RESOLUTION; ++iy) {
|
||||
for (int ix = 0; ix < VoxelGraphEditorNodePreview::RESOLUTION; ++ix) {
|
||||
{
|
||||
const int x = ix - VoxelGraphEditorNodePreview::RESOLUTION / 2;
|
||||
const int y = (VoxelGraphEditorNodePreview::RESOLUTION - iy) - VoxelGraphEditorNodePreview::RESOLUTION / 2;
|
||||
_graph->generate_single(Vector3i(x, y, 0));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < previews.size(); ++i) {
|
||||
PreviewInfo &info = previews[i];
|
||||
const float v = runtime.get_memory_value(info.address);
|
||||
const float g = clamp((v - info.min_value) * info.value_scale, 0.f, 1.f);
|
||||
Color c(g, g, g);
|
||||
info.control->get_image()->set_pixel(ix, iy, Color(g, g, g));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < previews.size(); ++i) {
|
||||
previews[i].control->get_image()->unlock();
|
||||
previews[i].control->update_texture();
|
||||
}
|
||||
|
||||
uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - time_before;
|
||||
print_line(String("Previews generated in {0} us").format(varray(time_taken)));
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::schedule_preview_update() {
|
||||
_time_before_preview_update = 0.5f;
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::_on_graph_changed() {
|
||||
schedule_preview_update();
|
||||
}
|
||||
|
||||
void VoxelGraphEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_on_graph_edit_gui_input", "event"), &VoxelGraphEditor::_on_graph_edit_gui_input);
|
||||
ClassDB::bind_method(D_METHOD("_on_graph_edit_connection_request", "from_node_name", "from_slot", "to_node_name", "to_slot"),
|
||||
@ -397,6 +544,8 @@ void VoxelGraphEditor::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_on_graph_edit_node_unselected"), &VoxelGraphEditor::_on_graph_edit_node_unselected);
|
||||
ClassDB::bind_method(D_METHOD("_on_graph_node_dragged", "from", "to", "id"), &VoxelGraphEditor::_on_graph_node_dragged);
|
||||
ClassDB::bind_method(D_METHOD("_on_context_menu_index_pressed", "idx"), &VoxelGraphEditor::_on_context_menu_index_pressed);
|
||||
ClassDB::bind_method(D_METHOD("_on_graph_changed"), &VoxelGraphEditor::_on_graph_changed);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_check_nothing_selected"), &VoxelGraphEditor::_check_nothing_selected);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("create_node_gui", "node_id"), &VoxelGraphEditor::create_node_gui);
|
||||
|
@ -23,12 +23,18 @@ public:
|
||||
void set_undo_redo(UndoRedo *undo_redo);
|
||||
|
||||
private:
|
||||
void _notification(int p_what);
|
||||
void _process(float delta);
|
||||
|
||||
void clear();
|
||||
void build_gui_from_graph();
|
||||
void create_node_gui(uint32_t node_id);
|
||||
void remove_node_gui(StringName gui_node_name);
|
||||
void set_node_position(int id, Vector2 offset);
|
||||
|
||||
void schedule_preview_update();
|
||||
void update_previews();
|
||||
|
||||
void _on_graph_edit_gui_input(Ref<InputEvent> event);
|
||||
void _on_graph_edit_connection_request(String from_node_name, int from_slot, String to_node_name, int to_slot);
|
||||
void _on_graph_edit_disconnection_request(String from_node_name, int from_slot, String to_node_name, int to_slot);
|
||||
@ -37,6 +43,7 @@ private:
|
||||
void _on_graph_edit_node_unselected(Node *p_node);
|
||||
void _on_graph_node_dragged(Vector2 from, Vector2 to, int id);
|
||||
void _on_context_menu_index_pressed(int idx);
|
||||
void _on_graph_changed();
|
||||
|
||||
void _check_nothing_selected();
|
||||
|
||||
@ -48,6 +55,7 @@ private:
|
||||
UndoRedo *_undo_redo = nullptr;
|
||||
Vector2 _click_position;
|
||||
bool _nothing_selected_check_scheduled = false;
|
||||
float _time_before_preview_update = 0.f;
|
||||
};
|
||||
|
||||
#endif // VOXEL_GRAPH_EDITOR_H
|
||||
|
@ -116,6 +116,7 @@ bool ProgramGraph::can_connect(PortLocation src, PortLocation dst) const {
|
||||
return false;
|
||||
}
|
||||
const Node *dst_node = get_node(dst.node_id);
|
||||
// There can be only one connection from a source to a destination
|
||||
return dst_node->inputs[dst.port_index].connections.size() == 0;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "../../util/profiling_clock.h"
|
||||
#include "voxel_graph_node_db.h"
|
||||
|
||||
#include <core/core_string_names.h>
|
||||
|
||||
VoxelGeneratorGraph::VoxelGeneratorGraph() {
|
||||
clear();
|
||||
clear_bounds();
|
||||
@ -47,6 +49,7 @@ ProgramGraph::Node *VoxelGeneratorGraph::create_node_internal(NodeTypeID type_id
|
||||
|
||||
void VoxelGeneratorGraph::remove_node(uint32_t node_id) {
|
||||
_graph.remove_node(node_id);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
bool VoxelGeneratorGraph::can_connect(uint32_t src_node_id, uint32_t src_port_index, uint32_t dst_node_id, uint32_t dst_port_index) const {
|
||||
@ -59,12 +62,14 @@ void VoxelGeneratorGraph::add_connection(uint32_t src_node_id, uint32_t src_port
|
||||
_graph.connect(
|
||||
ProgramGraph::PortLocation{ src_node_id, src_port_index },
|
||||
ProgramGraph::PortLocation{ dst_node_id, dst_port_index });
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void VoxelGeneratorGraph::remove_connection(uint32_t src_node_id, uint32_t src_port_index, uint32_t dst_node_id, uint32_t dst_port_index) {
|
||||
_graph.disconnect(
|
||||
ProgramGraph::PortLocation{ src_node_id, src_port_index },
|
||||
ProgramGraph::PortLocation{ dst_node_id, dst_port_index });
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void VoxelGeneratorGraph::get_connections(std::vector<ProgramGraph::Connection> &connections) const {
|
||||
@ -75,6 +80,18 @@ void VoxelGeneratorGraph::get_connections(std::vector<ProgramGraph::Connection>
|
||||
// _graph.get_connections_from_and_to(connections, node_id);
|
||||
//}
|
||||
|
||||
bool VoxelGeneratorGraph::try_get_connection_to(ProgramGraph::PortLocation dst, ProgramGraph::PortLocation &out_src) const {
|
||||
const ProgramGraph::Node *node = _graph.get_node(dst.node_id);
|
||||
CRASH_COND(node == nullptr);
|
||||
CRASH_COND(dst.port_index >= node->inputs.size());
|
||||
const ProgramGraph::Port &port = node->inputs[dst.port_index];
|
||||
if (port.connections.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
out_src = port.connections[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoxelGeneratorGraph::has_node(uint32_t node_id) const {
|
||||
return _graph.try_get_node(node_id) != nullptr;
|
||||
}
|
||||
@ -83,7 +100,24 @@ void VoxelGeneratorGraph::set_node_param(uint32_t node_id, uint32_t param_index,
|
||||
ProgramGraph::Node *node = _graph.try_get_node(node_id);
|
||||
ERR_FAIL_COND(node == nullptr);
|
||||
ERR_FAIL_INDEX(param_index, node->params.size());
|
||||
node->params[param_index] = value;
|
||||
|
||||
// TODO Changing sub-resources won't trigger a change signal
|
||||
// It's actually very annoying to setup and keep correct. Needs to be done cautiously.
|
||||
|
||||
// Ref<Resource> res = node->params[param_index];
|
||||
// if (res.is_valid()) {
|
||||
// res->disconnect(CoreStringNames::get_singleton()->changed, this, "_on_subresource_changed");
|
||||
// }
|
||||
|
||||
if (node->params[param_index] != value) {
|
||||
node->params[param_index] = value;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
// res = value;
|
||||
// if (res.is_valid()) {
|
||||
// res->connect(CoreStringNames::get_singleton()->changed, this, "_on_subresource_changed");
|
||||
// }
|
||||
}
|
||||
|
||||
Variant VoxelGeneratorGraph::get_node_param(uint32_t node_id, uint32_t param_index) const {
|
||||
@ -104,7 +138,10 @@ void VoxelGeneratorGraph::set_node_default_input(uint32_t node_id, uint32_t inpu
|
||||
ProgramGraph::Node *node = _graph.try_get_node(node_id);
|
||||
ERR_FAIL_COND(node == nullptr);
|
||||
ERR_FAIL_INDEX(input_index, node->default_inputs.size());
|
||||
node->default_inputs[input_index] = value;
|
||||
if (node->default_inputs[input_index] != value) {
|
||||
node->default_inputs[input_index] = value;
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 VoxelGeneratorGraph::get_node_gui_position(uint32_t node_id) const {
|
||||
@ -116,7 +153,11 @@ Vector2 VoxelGeneratorGraph::get_node_gui_position(uint32_t node_id) const {
|
||||
void VoxelGeneratorGraph::set_node_gui_position(uint32_t node_id, Vector2 pos) {
|
||||
ProgramGraph::Node *node = _graph.try_get_node(node_id);
|
||||
ERR_FAIL_COND(node == nullptr);
|
||||
node->gui_position = pos;
|
||||
if (node->gui_position != pos) {
|
||||
node->gui_position = pos;
|
||||
// Moving nodes around doesn't functionally change the graph
|
||||
//emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
VoxelGeneratorGraph::NodeTypeID VoxelGeneratorGraph::get_node_type_id(uint32_t node_id) const {
|
||||
@ -658,6 +699,10 @@ float VoxelGeneratorGraph::_b_generate_single(Vector3 pos) {
|
||||
return generate_single(Vector3i(pos));
|
||||
}
|
||||
|
||||
// void VoxelGeneratorGraph::_on_subresource_changed() {
|
||||
// emit_changed();
|
||||
// }
|
||||
|
||||
void VoxelGeneratorGraph::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("clear"), &VoxelGeneratorGraph::clear);
|
||||
ClassDB::bind_method(D_METHOD("create_node", "type_id", "position", "id"), &VoxelGeneratorGraph::create_node, DEFVAL(ProgramGraph::NULL_ID));
|
||||
@ -690,6 +735,8 @@ void VoxelGeneratorGraph::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_set_graph_data", "data"), &VoxelGeneratorGraph::load_graph_from_variant_data);
|
||||
ClassDB::bind_method(D_METHOD("_get_graph_data"), &VoxelGeneratorGraph::get_graph_as_variant_data);
|
||||
|
||||
// ClassDB::bind_method(D_METHOD("_on_subresource_changed"), &VoxelGeneratorGraph::_on_subresource_changed);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "graph_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL),
|
||||
"_set_graph_data", "_get_graph_data");
|
||||
|
||||
@ -725,5 +772,6 @@ void VoxelGeneratorGraph::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(NODE_SDF_BOX);
|
||||
BIND_ENUM_CONSTANT(NODE_SDF_SPHERE);
|
||||
BIND_ENUM_CONSTANT(NODE_SDF_TORUS);
|
||||
BIND_ENUM_CONSTANT(NODE_SDF_PREVIEW);
|
||||
BIND_ENUM_CONSTANT(NODE_TYPE_COUNT);
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
NODE_SDF_BOX,
|
||||
NODE_SDF_SPHERE,
|
||||
NODE_SDF_TORUS,
|
||||
NODE_SDF_PREVIEW, // For debugging
|
||||
NODE_TYPE_COUNT
|
||||
};
|
||||
|
||||
@ -57,6 +58,7 @@ public:
|
||||
void remove_connection(uint32_t src_node_id, uint32_t src_port_index, uint32_t dst_node_id, uint32_t dst_port_index);
|
||||
void get_connections(std::vector<ProgramGraph::Connection> &connections) const;
|
||||
//void get_connections_from_and_to(std::vector<ProgramGraph::Connection> &connections, uint32_t node_id) const;
|
||||
bool try_get_connection_to(ProgramGraph::PortLocation dst, ProgramGraph::PortLocation &out_src) const;
|
||||
|
||||
bool has_node(uint32_t node_id) const;
|
||||
|
||||
@ -91,13 +93,17 @@ public:
|
||||
|
||||
Ref<Resource> duplicate(bool p_subresources) const override;
|
||||
|
||||
// Internal
|
||||
|
||||
const VoxelGraphRuntime &get_runtime() const { return _runtime; }
|
||||
void compile();
|
||||
|
||||
// Debug
|
||||
|
||||
float debug_measure_microseconds_per_voxel();
|
||||
void debug_load_waves_preset();
|
||||
|
||||
private:
|
||||
void compile();
|
||||
Interval analyze_range(Vector3i min_pos, Vector3i max_pos);
|
||||
|
||||
ProgramGraph::Node *create_node_internal(NodeTypeID type_id, Vector2 position, uint32_t id);
|
||||
@ -118,6 +124,9 @@ private:
|
||||
void _b_set_node_param_null(int node_id, int param_index);
|
||||
float _b_generate_single(Vector3 pos);
|
||||
|
||||
void _on_subresource_changed();
|
||||
void connect_to_subresource_changes();
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
struct Bounds {
|
||||
|
@ -258,6 +258,14 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
||||
t.inputs.push_back(Port("radius2", 4.f));
|
||||
t.outputs.push_back(Port("sdf"));
|
||||
}
|
||||
{
|
||||
NodeType &t = types[VoxelGeneratorGraph::NODE_SDF_PREVIEW];
|
||||
t.name = "SdfPreview";
|
||||
t.inputs.push_back(Port("value"));
|
||||
t.params.push_back(Param("min_value", Variant::REAL, -1.f));
|
||||
t.params.push_back(Param("max_value", Variant::REAL, 1.f));
|
||||
t.debug_only = true;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _types.size(); ++i) {
|
||||
NodeType &t = _types[i];
|
||||
|
@ -40,6 +40,8 @@ public:
|
||||
|
||||
struct NodeType {
|
||||
String name;
|
||||
bool debug_only = false;
|
||||
// TODO Category
|
||||
std::vector<Port> inputs;
|
||||
std::vector<Port> outputs;
|
||||
std::vector<Param> params;
|
||||
|
@ -181,15 +181,23 @@ void VoxelGraphRuntime::clear() {
|
||||
_xzy_program_start = 0;
|
||||
_last_x = INT_MAX;
|
||||
_last_z = INT_MAX;
|
||||
_output_port_addresses.clear();
|
||||
}
|
||||
|
||||
void VoxelGraphRuntime::compile(const ProgramGraph &graph) {
|
||||
_output_port_addresses.clear();
|
||||
|
||||
std::vector<uint32_t> order;
|
||||
std::vector<uint32_t> terminal_nodes;
|
||||
|
||||
graph.find_terminal_nodes(terminal_nodes);
|
||||
// For now only 1 end is supported
|
||||
ERR_FAIL_COND(terminal_nodes.size() != 1);
|
||||
|
||||
// Exclude debug nodes
|
||||
unordered_remove_if(terminal_nodes, [&graph](uint32_t node_id) {
|
||||
const ProgramGraph::Node *node = graph.get_node(node_id);
|
||||
const VoxelGraphNodeDB::NodeType &type = VoxelGraphNodeDB::get_singleton()->get_type(node->type_id);
|
||||
return type.debug_only;
|
||||
});
|
||||
|
||||
graph.find_dependencies(terminal_nodes.back(), order);
|
||||
|
||||
@ -271,7 +279,6 @@ void VoxelGraphRuntime::compile(const ProgramGraph &graph) {
|
||||
|
||||
std::vector<uint8_t> &program = _program;
|
||||
const VoxelGraphNodeDB &type_db = *VoxelGraphNodeDB::get_singleton();
|
||||
HashMap<ProgramGraph::PortLocation, uint16_t, ProgramGraph::PortLocationHasher> output_port_addresses;
|
||||
bool has_output = false;
|
||||
|
||||
// Run through each node in order, and turn them into program instructions
|
||||
@ -294,19 +301,19 @@ void VoxelGraphRuntime::compile(const ProgramGraph &graph) {
|
||||
CRASH_COND(type.params.size() != 1);
|
||||
uint16_t a = _memory.size();
|
||||
_memory.push_back(node->params[0].operator float());
|
||||
output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = a;
|
||||
_output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = a;
|
||||
} break;
|
||||
|
||||
case VoxelGeneratorGraph::NODE_INPUT_X:
|
||||
output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = 0;
|
||||
_output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = 0;
|
||||
break;
|
||||
|
||||
case VoxelGeneratorGraph::NODE_INPUT_Y:
|
||||
output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = 1;
|
||||
_output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = 1;
|
||||
break;
|
||||
|
||||
case VoxelGeneratorGraph::NODE_INPUT_Z:
|
||||
output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = 2;
|
||||
_output_port_addresses[ProgramGraph::PortLocation{ node_id, 0 }] = 2;
|
||||
break;
|
||||
|
||||
case VoxelGeneratorGraph::NODE_OUTPUT_SDF:
|
||||
@ -337,7 +344,7 @@ void VoxelGraphRuntime::compile(const ProgramGraph &graph) {
|
||||
|
||||
} else {
|
||||
ProgramGraph::PortLocation src_port = node->inputs[j].connections[0];
|
||||
const uint16_t *aptr = output_port_addresses.getptr(src_port);
|
||||
const uint16_t *aptr = _output_port_addresses.getptr(src_port);
|
||||
// Previous node ports must have been registered
|
||||
CRASH_COND(aptr == nullptr);
|
||||
a = *aptr;
|
||||
@ -353,7 +360,7 @@ void VoxelGraphRuntime::compile(const ProgramGraph &graph) {
|
||||
|
||||
// This will be used by next nodes
|
||||
const ProgramGraph::PortLocation op{ node_id, static_cast<uint32_t>(j) };
|
||||
output_port_addresses[op] = a;
|
||||
_output_port_addresses[op] = a;
|
||||
|
||||
append(program, a);
|
||||
}
|
||||
@ -980,3 +987,14 @@ Interval VoxelGraphRuntime::analyze_range(Vector3i min_pos, Vector3i max_pos) {
|
||||
|
||||
return Interval(min_memory[min_memory.size() - 1], max_memory[max_memory.size() - 1]);
|
||||
}
|
||||
|
||||
uint16_t VoxelGraphRuntime::get_output_port_address(ProgramGraph::PortLocation port) const {
|
||||
const uint16_t *aptr = _output_port_addresses.getptr(port);
|
||||
ERR_FAIL_COND_V(aptr == nullptr, 0);
|
||||
return *aptr;
|
||||
}
|
||||
|
||||
float VoxelGraphRuntime::get_memory_value(uint16_t address) const {
|
||||
CRASH_COND(address >= _memory.size());
|
||||
return _memory[address];
|
||||
}
|
||||
|
@ -15,12 +15,18 @@ public:
|
||||
float generate_single(const Vector3i &position);
|
||||
Interval analyze_range(Vector3i min_pos, Vector3i max_pos);
|
||||
|
||||
// Debugging
|
||||
uint16_t get_output_port_address(ProgramGraph::PortLocation port) const;
|
||||
float get_memory_value(uint16_t address) const;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _program;
|
||||
std::vector<float> _memory;
|
||||
uint32_t _xzy_program_start;
|
||||
int _last_x;
|
||||
int _last_z;
|
||||
|
||||
HashMap<ProgramGraph::PortLocation, uint16_t, ProgramGraph::PortLocationHasher> _output_port_addresses;
|
||||
};
|
||||
|
||||
#endif // VOXEL_GRAPH_RUNTIME_H
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
// For interval arithmetic
|
||||
struct Interval {
|
||||
|
||||
// Both inclusive
|
||||
float min;
|
||||
float max;
|
||||
|
@ -50,6 +50,8 @@ inline void unordered_remove_if(std::vector<T> &vec, F predicate) {
|
||||
if (predicate(vec[i])) {
|
||||
vec[i] = vec.back();
|
||||
vec.pop_back();
|
||||
// Note: can underflow, but it should be fine since it's incremented right after.
|
||||
// TODO Use a while()?
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user