diff --git a/modules/material_maker/editor/widgets/tones_editor/tones_editor.cpp b/modules/material_maker/editor/widgets/tones_editor/tones_editor.cpp index 0f042537a..8d7482ffb 100644 --- a/modules/material_maker/editor/widgets/tones_editor/tones_editor.cpp +++ b/modules/material_maker/editor/widgets/tones_editor/tones_editor.cpp @@ -11,6 +11,8 @@ #include "../../../algos/mm_algos.h" +#include "tones_editor_cursor.h" + void MMTonesEditor::set_value(const Ref &v) { if (_node == v) { return; @@ -29,6 +31,123 @@ void MMTonesEditor::set_value(const Ref &v) { on_input_property_changed(); } +enum ParameterTypes { + PARAMETER_TYPE_IN_MIN = 0, + PARAMETER_TYPE_IN_MID, + PARAMETER_TYPE_IN_MAX, + PARAMETER_TYPE_OUT_MIN, + PARAMETER_TYPE_OUT_MAX, +}; + +Color MMTonesEditor::get_parameter(ParameterTypes type) { + if (!_node.is_valid()) { + return Color(); + } + + switch (type) { + case PARAMETER_TYPE_IN_MIN: + return _node->get_in_min(); + break; + case PARAMETER_TYPE_IN_MID: + return _node->get_in_mid(); + break; + case PARAMETER_TYPE_IN_MAX: + return _node->get_in_max(); + break; + case PARAMETER_TYPE_OUT_MIN: + return _node->get_out_min(); + break; + case PARAMETER_TYPE_OUT_MAX: + return _node->get_out_max(); + break; + default: + break; + } + + return Color(); +} + +float MMTonesEditor::get_parameter_current_mode(ParameterTypes type) { + Color color = get_parameter(type); + + switch (_current_mode) { + case MODE_LUMINANCE: + return (color.r + color.g + color.b) / 3.0; + break; + case MODE_RED: + return color.r; + break; + case MODE_GREEN: + return color.g; + break; + case MODE_BLUE: + return color.b; + break; + case MODE_ALPHA: + return color.a; + break; + } + + return 0; +} + +void MMTonesEditor::set_parameter(ParameterTypes type, const Color &val) { + if (!_node.is_valid()) { + return; + } + + switch (type) { + case PARAMETER_TYPE_IN_MIN: + _node->set_in_min(val); + break; + case PARAMETER_TYPE_IN_MID: + _node->set_in_mid(val); + break; + case PARAMETER_TYPE_IN_MAX: + _node->set_in_max(val); + break; + case PARAMETER_TYPE_OUT_MIN: + _node->set_out_min(val); + break; + case PARAMETER_TYPE_OUT_MAX: + _node->set_out_max(val); + break; + default: + break; + } +} + +void MMTonesEditor::set_parameter_current_mode(ParameterTypes type, float val, float d) { + if (!_node.is_valid()) { + return; + } + + Color color = get_parameter(type); + + switch (_current_mode) { + case MODE_LUMINANCE: + color.r = val; + color.g = val; + color.b = val; + color.a = d; + break; + case MODE_RED: + color.r = val; + break; + case MODE_GREEN: + color.g = val; + break; + case MODE_BLUE: + color.b = val; + break; + case MODE_ALPHA: + color.a = val; + break; + } + + set_parameter(type, color); +} + Ref MMTonesEditor::make_histogram(const Ref &img) { ERR_FAIL_COND_V(!img.is_valid(), Ref()); @@ -66,9 +185,11 @@ MMTonesEditor::MMTonesEditor() { _mode_ob->add_item("Alpha", MODE_ALPHA); _mode_ob->select(MODE_LUMINANCE); + _mode_ob->connect("item_selected", this, "on_mode_item_selected"); Button *auto_button = memnew(Button); bar->add_child(auto_button); + auto_button->connect("pressed", this, "on_auto_levels_pressed"); auto_button->set_text("AL"); auto_button->set_tooltip("Set levels automatically"); @@ -83,9 +204,35 @@ MMTonesEditor::MMTonesEditor() { _histogram_tr->set_h_size_flags(Control::SIZE_EXPAND_FILL); add_child(_histogram_tr); + _cursor_in_min = memnew(MMTonesEditorCursor); + _cursor_in_mid = memnew(MMTonesEditorCursor); + _cursor_in_max = memnew(MMTonesEditorCursor); + _cursor_out_min = memnew(MMTonesEditorCursor); + _cursor_out_max = memnew(MMTonesEditorCursor); + + _cursor_in_min->initialize(Color(0, 0, 0), 0, true); + _cursor_in_mid->initialize(Color(0.5, 0.5, 0.5), 0.5, true); + _cursor_in_max->initialize(Color(1, 1, 1), 1, true); + _cursor_out_min->initialize(Color(0, 0, 0), 0, false); + _cursor_out_max->initialize(Color(1, 1, 1), 1, false); + + _histogram_tr->add_child(_cursor_in_min); + _histogram_tr->add_child(_cursor_in_mid); + _histogram_tr->add_child(_cursor_in_max); + _histogram_tr->add_child(_cursor_out_min); + _histogram_tr->add_child(_cursor_out_max); + + _cursor_in_min->connect("cursor_value_changed", this, "on_cursor_value_changed"); + _cursor_in_mid->connect("cursor_value_changed", this, "on_cursor_value_changed"); + _cursor_in_max->connect("cursor_value_changed", this, "on_cursor_value_changed"); + _cursor_out_min->connect("cursor_value_changed", this, "on_cursor_value_changed"); + _cursor_out_max->connect("cursor_value_changed", this, "on_cursor_value_changed"); + spacer = memnew(Control); spacer->set_custom_minimum_size(Vector2(0, 4)); add_child(spacer); + + on_mode_item_selected(MODE_LUMINANCE); } MMTonesEditor::~MMTonesEditor() { @@ -107,6 +254,85 @@ void MMTonesEditor::on_input_property_changed() { _histogram_tr->set_texture(make_histogram(img)); } +void MMTonesEditor::on_auto_levels_pressed() { + // TODO needs proper histogram generation + /* + var histogram = $Histogram.get_histogram_texture().get_data() + histogram.lock() + var in_min : int = -1 + var in_mid : int = -1 + var in_mid_value : float = 0 + var in_max : int = -1 + var histogram_size = histogram.get_size().x + for i in range(histogram_size): + var color : Color = histogram.get_pixel(i, 0) + var value : float + match $Bar/Mode.selected: + 0: + value = (color.r+color.g+color.b)/3.0 + 1: + value = color.r + 2: + value = color.g + 3: + value = color.b + 4: + value = color.a + if value > 0.0: + if in_min == -1: + in_min = i + in_max = i + if in_mid_value < value: + in_mid = i + in_mid_value = value + histogram.unlock() + cursor_in_min.update_value(in_min/(histogram_size-1)) + cursor_in_mid.update_value(in_mid/(histogram_size-1)) + cursor_in_max.update_value(in_max/(histogram_size-1)) + */ +} + +void MMTonesEditor::on_mode_item_selected(int id) { + _current_mode = static_cast(id); + + _cursor_in_min->set_value(get_parameter_current_mode(PARAMETER_TYPE_IN_MIN)); + _cursor_in_mid->set_value(get_parameter_current_mode(PARAMETER_TYPE_IN_MID)); + _cursor_in_max->set_value(get_parameter_current_mode(PARAMETER_TYPE_IN_MAX)); + _cursor_out_min->set_value(get_parameter_current_mode(PARAMETER_TYPE_OUT_MIN)); + _cursor_out_max->set_value(get_parameter_current_mode(PARAMETER_TYPE_OUT_MAX)); +} + +void MMTonesEditor::on_cursor_value_changed(Control *cursor, float position) { + if (cursor == _cursor_in_min) { + set_parameter_current_mode(PARAMETER_TYPE_IN_MIN, position, 0); + } else if (cursor == _cursor_in_mid) { + set_parameter_current_mode(PARAMETER_TYPE_IN_MID, position, 0.5); + } else if (cursor == _cursor_in_max) { + set_parameter_current_mode(PARAMETER_TYPE_IN_MAX, position, 1); + } else if (cursor == _cursor_out_min) { + set_parameter_current_mode(PARAMETER_TYPE_OUT_MIN, position, 0); + } else if (cursor == _cursor_out_max) { + set_parameter_current_mode(PARAMETER_TYPE_OUT_MAX, position, 1); + } +} + +void MMTonesEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_RESIZED: { + _cursor_in_min->resize(); + _cursor_in_mid->resize(); + _cursor_in_max->resize(); + _cursor_out_min->resize(); + _cursor_out_max->resize(); + } break; + default: + break; + } +} + void MMTonesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("on_input_property_changed"), &MMTonesEditor::on_input_property_changed); + ClassDB::bind_method(D_METHOD("on_auto_levels_pressed"), &MMTonesEditor::on_auto_levels_pressed); + ClassDB::bind_method(D_METHOD("on_mode_item_selected"), &MMTonesEditor::on_mode_item_selected); + ClassDB::bind_method(D_METHOD("on_cursor_value_changed"), &MMTonesEditor::on_cursor_value_changed); } diff --git a/modules/material_maker/editor/widgets/tones_editor/tones_editor.h b/modules/material_maker/editor/widgets/tones_editor/tones_editor.h index 6beac3e86..068fe163e 100644 --- a/modules/material_maker/editor/widgets/tones_editor/tones_editor.h +++ b/modules/material_maker/editor/widgets/tones_editor/tones_editor.h @@ -9,6 +9,7 @@ class MMTones; class OptionButton; class TextureRect; class ImageTexture; +class MMTonesEditorCursor; class MMTonesEditor : public VBoxContainer { GDCLASS(MMTonesEditor, VBoxContainer); @@ -28,6 +29,20 @@ public: void set_value(const Ref &v); + enum ParameterTypes { + PARAMETER_TYPE_IN_MIN = 0, + PARAMETER_TYPE_IN_MID, + PARAMETER_TYPE_IN_MAX, + PARAMETER_TYPE_OUT_MIN, + PARAMETER_TYPE_OUT_MAX, + }; + + Color get_parameter(ParameterTypes type); + float get_parameter_current_mode(ParameterTypes type); + + void set_parameter(ParameterTypes type, const Color &val); + void set_parameter_current_mode(ParameterTypes type, float val, float d); + Ref make_histogram(const Ref &img); Ref make_default_histogram(); @@ -36,13 +51,26 @@ public: protected: void on_input_property_changed(); + void on_auto_levels_pressed(); + void on_mode_item_selected(int id); + void on_cursor_value_changed(Control *cursor, float position); + + void _notification(int p_what); static void _bind_methods(); Ref _node; + Modes _current_mode; + OptionButton *_mode_ob; TextureRect *_histogram_tr; + + MMTonesEditorCursor *_cursor_in_min; + MMTonesEditorCursor *_cursor_in_mid; + MMTonesEditorCursor *_cursor_in_max; + MMTonesEditorCursor *_cursor_out_min; + MMTonesEditorCursor *_cursor_out_max; }; #endif diff --git a/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.cpp b/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.cpp index 85be0c1ad..08f37bd3a 100644 --- a/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.cpp +++ b/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.cpp @@ -1,11 +1,122 @@ #include "tones_editor_cursor.h" +void MMTonesEditorCursor::set_value(float val) { + _position = val; + + Control *parent = get_parent_control(); + + if (!parent) { + return; + } + + Vector2 pos = get_position(); + set_position(Vector2(_position * parent->get_size().x - 0.5 * CURSOR_WIDTH, pos.y)); +} + +void MMTonesEditorCursor::update_value(float val) { + if (!Math::is_equal_approx(val, _position)) { + set_value(val); + emit_signal("cursor_value_changed", this, _position); + update(); + } +} + +void MMTonesEditorCursor::initialize(const Color &color, float position, bool top) { + _color = color; + _position = position; + _top = top; +} + +void MMTonesEditorCursor::resize() { + Control *parent = get_parent_control(); + + if (!parent) { + return; + } + + Vector2 position = get_position(); + + if (_top) { + set_position(Vector2(position.x, -2)); + } else { + set_position(Vector2(position.x, parent->get_size().y + 2 - CURSOR_HEIGHT)); + } + + set_size(Vector2(CURSOR_WIDTH, CURSOR_HEIGHT)); + set_value(_position); +} + +void MMTonesEditorCursor::_gui_input(const Ref &p_event) { + Ref iemm = p_event; + + if (iemm.is_valid()) { + if (((iemm->get_button_mask() & 1) != 0)) { + Control *parent = get_parent_control(); + + if (!parent) { + return; + } + + Vector2 parent_size = parent->get_size(); + + Vector2 pos = get_position(); + + pos.x += iemm->get_relative().x; + pos.x = MIN(MAX(-0.5 * CURSOR_WIDTH, pos.x), parent_size.x - 0.5 * CURSOR_WIDTH); + + update_value((pos.x + 0.5 * CURSOR_WIDTH) / parent_size.x); + } + } +} + MMTonesEditorCursor::MMTonesEditorCursor() { } MMTonesEditorCursor::~MMTonesEditorCursor() { } -void MMTonesEditorCursor::_bind_methods() { +void MMTonesEditorCursor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + Vector polygon; + polygon.resize(4); + + if (_top) { + polygon.write[0] = Vector2(0, 0); + polygon.write[1] = Vector2(CURSOR_WIDTH / 2.0, CURSOR_HEIGHT); + polygon.write[2] = Vector2(CURSOR_WIDTH, 0); + polygon.write[3] = Vector2(0, 0); + } else { + polygon.write[0] = Vector2(0, CURSOR_HEIGHT); + polygon.write[1] = Vector2(CURSOR_WIDTH / 2.0, 0); + polygon.write[2] = Vector2(CURSOR_WIDTH, CURSOR_HEIGHT); + polygon.write[3] = Vector2(0, CURSOR_HEIGHT); + } + + Color c = _color; + c.a = 1.0; + draw_colored_polygon(polygon, c); + float outline_color = 0; + + if (_position < 0.5) { + outline_color = 1.0; + } + + draw_polyline(polygon, Color(outline_color, outline_color, outline_color), 1.0, true); + + } break; + case NOTIFICATION_RESIZED: + case NOTIFICATION_READY: { + resize(); + } break; + default: + break; + } +} + +void MMTonesEditorCursor::_bind_methods() { + ADD_SIGNAL(MethodInfo("cursor_value_changed", PropertyInfo(Variant::OBJECT, "cursor", PROPERTY_HINT_RESOURCE_TYPE, "Control"), PropertyInfo(Variant::REAL, "position"))); + + ClassDB::bind_method(D_METHOD("_gui_input"), &MMTonesEditorCursor::_gui_input); } diff --git a/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.h b/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.h index aeaa66774..ff5acc996 100644 --- a/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.h +++ b/modules/material_maker/editor/widgets/tones_editor/tones_editor_cursor.h @@ -7,11 +7,30 @@ class MMTonesEditorCursor : public TextureRect { GDCLASS(MMTonesEditorCursor, TextureRect); public: + enum { + CURSOR_WIDTH = 12, + CURSOR_HEIGHT = 12, + }; + + void set_value(float val); + void update_value(float val); + + void initialize(const Color &color, float position, bool top); + + void resize(); + + void _gui_input(const Ref &p_event); + MMTonesEditorCursor(); ~MMTonesEditorCursor(); protected: + void _notification(int p_what); static void _bind_methods(); + + Color _color; + float _position; + bool _top; }; #endif