tool extends Control const Brush = preload("./terrain_painter.gd") const Errors = preload("../../util/errors.gd") #const NativeFactory = preload("../../native/factory.gd") const Logger = preload("../../util/logger.gd") const SHAPES_DIR = "addons/zylann.hterrain/tools/brush/shapes" const DEFAULT_BRUSH = "round2.exr" onready var _size_slider := $GridContainer/BrushSizeControl/Slider as Slider onready var _size_value_label := $GridContainer/BrushSizeControl/Label as Label #onready var _size_label = _params_container.get_node("BrushSizeLabel") onready var _opacity_slider = $GridContainer/BrushOpacityControl/Slider onready var _opacity_value_label = $GridContainer/BrushOpacityControl/Label onready var _opacity_control = $GridContainer/BrushOpacityControl onready var _opacity_label = $GridContainer/BrushOpacityLabel onready var _flatten_height_container = $GridContainer/HB onready var _flatten_height_box = $GridContainer/HB/FlattenHeightControl onready var _flatten_height_label = $GridContainer/FlattenHeightLabel onready var _flatten_height_pick_button = $GridContainer/HB/FlattenHeightPickButton onready var _color_picker = $GridContainer/ColorPickerButton onready var _color_label = $GridContainer/ColorLabel onready var _density_slider = $GridContainer/DensitySlider onready var _density_label = $GridContainer/DensityLabel onready var _holes_label = $GridContainer/HoleLabel onready var _holes_checkbox = $GridContainer/HoleCheckbox onready var _slope_limit_label = $GridContainer/SlopeLimitLabel onready var _slope_limit_control = $GridContainer/SlopeLimit onready var _shape_texture_rect = get_node("BrushShapeButton/TextureRect") var _brush : Brush var _load_image_dialog = null var _logger = Logger.get_for(self) # TODO This is an ugly workaround for https://github.com/godotengine/godot/issues/19479 onready var _temp_node = get_node("Temp") onready var _grid_container = get_node("GridContainer") func _set_visibility_of(node: Control, v: bool): node.get_parent().remove_child(node) if v: _grid_container.add_child(node) else: _temp_node.add_child(node) node.visible = v func _ready(): _size_slider.connect("value_changed", self, "_on_size_slider_value_changed") _opacity_slider.connect("value_changed", self, "_on_opacity_slider_value_changed") _flatten_height_box.connect("value_changed", self, "_on_flatten_height_box_value_changed") _color_picker.connect("color_changed", self, "_on_color_picker_color_changed") _density_slider.connect("value_changed", self, "_on_density_slider_changed") _holes_checkbox.connect("toggled", self, "_on_holes_checkbox_toggled") _slope_limit_control.connect("changed", self, "_on_slope_limit_changed") _size_slider.max_value = 200 #if NativeFactory.is_native_available(): # _size_slider.max_value = 200 #else: # _size_slider.max_value = 50 func setup_dialogs(base_control: Control): assert(_load_image_dialog == null) _load_image_dialog = EditorFileDialog.new() _load_image_dialog.mode = EditorFileDialog.MODE_OPEN_FILE _load_image_dialog.add_filter("*.exr ; EXR files") _load_image_dialog.resizable = true _load_image_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM _load_image_dialog.current_dir = SHAPES_DIR _load_image_dialog.connect("file_selected", self, "_on_LoadImageDialog_file_selected") base_control.add_child(_load_image_dialog) func _exit_tree(): if _load_image_dialog != null: _load_image_dialog.queue_free() _load_image_dialog = null # Testing display modes #var mode = 0 #func _input(event): # if event is InputEventKey: # if event.pressed: # set_display_mode(mode) # mode += 1 # if mode >= Brush.MODE_COUNT: # mode = 0 func set_brush(brush: Brush): if _brush != null: _brush.disconnect("changed", self, "_on_brush_changed") _brush = brush if brush != null: # TODO Had an issue in Godot 3.2.3 where mismatching type would silently cast to null... # It happens if the argument went through a Variant (for example if call_deferred is used) assert(_brush != null) if _brush != null: # Initial params _size_slider.value = brush.get_brush_size() _opacity_slider.ratio = brush.get_opacity() _flatten_height_box.value = brush.get_flatten_height() _color_picker.get_picker().color = brush.get_color() _density_slider.value = brush.get_detail_density() _holes_checkbox.pressed = not brush.get_mask_flag() var low = rad2deg(brush.get_slope_limit_low_angle()) var high = rad2deg(brush.get_slope_limit_high_angle()) _slope_limit_control.set_values(low, high) set_display_mode(brush.get_mode()) _set_brush_shape_from_file(SHAPES_DIR.plus_file(DEFAULT_BRUSH)) _brush.connect("changed", self, "_on_brush_properties_changed") func _on_brush_properties_changed(): _flatten_height_box.value = _brush.get_flatten_height() _flatten_height_pick_button.pressed = false func set_display_mode(mode: int): var show_flatten := mode == Brush.MODE_FLATTEN var show_color := mode == Brush.MODE_COLOR var show_density := mode == Brush.MODE_DETAIL var show_opacity := mode != Brush.MODE_MASK var show_holes := mode == Brush.MODE_MASK var show_slope_limit := mode == Brush.MODE_SPLAT _set_visibility_of(_opacity_label, show_opacity) _set_visibility_of(_opacity_control, show_opacity) _set_visibility_of(_color_label, show_color) _set_visibility_of(_color_picker, show_color) _set_visibility_of(_flatten_height_label, show_flatten) _set_visibility_of(_flatten_height_container, show_flatten) _set_visibility_of(_density_label, show_density) _set_visibility_of(_density_slider, show_density) _set_visibility_of(_holes_label, show_holes) _set_visibility_of(_holes_checkbox, show_holes) _set_visibility_of(_slope_limit_label, show_slope_limit) _set_visibility_of(_slope_limit_control, show_slope_limit) _flatten_height_pick_button.pressed = false func _on_size_slider_value_changed(v: float): if _brush != null: _brush.set_brush_size(int(v)) _size_value_label.text = str(v) func _on_opacity_slider_value_changed(v: float): if _brush != null: _brush.set_opacity(_opacity_slider.ratio) _opacity_value_label.text = str(v) func _on_flatten_height_box_value_changed(v: float): if _brush != null: _brush.set_flatten_height(v) func _on_color_picker_color_changed(v: Color): if _brush != null: _brush.set_color(v) func _on_density_slider_changed(v: float): if _brush != null: _brush.set_detail_density(v) func _on_holes_checkbox_toggled(v: bool): if _brush != null: # When checked, we draw holes. When unchecked, we clear holes _brush.set_mask_flag(not v) func _on_BrushShapeButton_pressed(): _load_image_dialog.popup_centered_ratio(0.7) func _on_LoadImageDialog_file_selected(path: String): _set_brush_shape_from_file(path) func _set_brush_shape_from_file(path: String): var im := Image.new() var err := im.load(path) if err != OK: _logger.error("Could not load image at '{0}', error {1}" \ .format([path, Errors.get_message(err)])) return var tex := ImageTexture.new() tex.create_from_image(im, Texture.FLAG_FILTER) if _brush != null: var im2 := im var v := Engine.get_version_info() if v.major == 3 and v.minor < 1: # Forcing image brushes would ruin resized ones, # due to https://github.com/godotengine/godot/issues/24244 if path.find(SHAPES_DIR.plus_file(DEFAULT_BRUSH)) != -1: im2 = null _brush.set_brush_texture(tex) _shape_texture_rect.texture = tex func _on_FlattenHeightPickButton_pressed(): _brush.set_meta("pick_height", true) func _on_slope_limit_changed(): var low = deg2rad(_slope_limit_control.get_low_value()) var high = deg2rad(_slope_limit_control.get_high_value()) _brush.set_slope_limit_angles(low, high)