extends Control signal params_loaded signal params_reset @export var shader: ShaderMaterial var loaded_images := {} var loaded_image_paths := {} var image_modification_times := {} var trans_tween = null var params := ImagineParams.new() var time = 0.0 var time_scale_factor = 1.0 var fx_path = "" # Called when the node enters the scene tree for the first time. func _ready() -> void: params.time_scale = 0.01 params.transition_dur = 2 %LoadImageButton.pressed.connect(func(): %LoadImageDialog.visible = true ) %LoadImageDialog.files_selected.connect(func(paths): for p in paths: load_image(p) ) %SaveFXButton.pressed.connect(func(): if fx_path == "": %SaveFXDialog.visible = true else: save_effects() ) %SaveFXAsButton.pressed.connect(func(): %SaveFXDialog.visible = true ) %SaveFXDialog.file_selected.connect(func(path): fx_path = path save_effects() ) %LoadFXDialog.file_selected.connect(func(path): fx_path = path params = ResourceLoader.load(path) params_loaded.emit() %FXFileLabel.text = fx_path ) %LoadFXButton.pressed.connect(func(): %LoadFXDialog.visible = true ) %NewFXButton.pressed.connect(func(): params = ImagineParams.new() fx_path = "" %FXFileLabel.text = "unsaved FX" params_reset.emit() ) %ImageList.item_clicked.connect(func(index, at, btn): if btn == MouseButton.MOUSE_BUTTON_LEFT: transition_to_image(%ImageList.get_item_text(index)) elif btn == MouseButton.MOUSE_BUTTON_RIGHT && Input.is_action_pressed("shift"): var file = %ImageList.get_item_text(index) loaded_images.erase(file) loaded_image_paths.erase(file) image_modification_times.erase(file) %ImageList.remove_item(index) ) for child in %Params.get_children(): link_param(child) func save_effects(): ResourceSaver.save(params, fx_path) %FXFileLabel.text = fx_path %SaveConfirmPopup.dialog_text = "FX saved to %s" % fx_path %SaveConfirmPopup.show() func _process(delta): if Input.is_action_just_pressed("toggle_fullscreen"): %ControlSide.visible = !%ControlSide.visible time += delta * params.time_scale * time_scale_factor shader.set_shader_parameter("time", time) for path in loaded_image_paths.values(): var prev_mod = image_modification_times[path.get_file()] var last_mod = FileAccess.get_modified_time(path) if last_mod > prev_mod: load_image(path) func load_image(path: String): var file = path.get_file() var image = Image.load_from_file(path) if image == null: return var tex = ImageTexture.create_from_image(image) if file in loaded_images: for i in range(%ImageList.item_count): var txt = %ImageList.get_item_text(i) if txt == file: %ImageList.set_item_icon(i, tex) print("Reloaded %s" % txt) var prev_tex = loaded_images[file] if shader.get_shader_parameter("texture1") == prev_tex: shader.set_shader_parameter("texture1", tex) if shader.get_shader_parameter("texture2") == prev_tex: shader.set_shader_parameter("texture2", tex) else: %ImageList.add_item(file, tex) loaded_images[file] = tex loaded_image_paths[file] = path image_modification_times[file] = FileAccess.get_modified_time(path) func transition_to_image(file: String): if trans_tween != null: if trans_tween.is_running(): return trans_tween.kill() var texture1 = shader.get_shader_parameter("texture1") var texture2 = loaded_images[file] shader.set_shader_parameter("texture2", texture2) var tw = create_tween() trans_tween = tw var set_trans = func(x): shader.set_shader_parameter("transition", x) tw.tween_callback(func(): time_scale_factor = 5) tw.tween_method(set_trans, 0.0, 1.0, params.transition_dur/2).set_trans(Tween.TRANS_SINE) tw.tween_callback(func(): shader.set_shader_parameter("texture1", texture2) shader.set_shader_parameter("texture2", texture1) ) tw.tween_method(set_trans, 1.0, 0.0, params.transition_dur/2).set_trans(Tween.TRANS_SINE) tw.tween_callback(func(): time_scale_factor = 1) func link_param(node: Node): if node is Label: return var param = node.name.to_snake_case() var slider = node.get_node("Slider") var button = node.get_node("ResetButton") var val = shader.get_shader_parameter(param) if param == "time_scale": slider.value = params.time_scale elif param == "frequency": var noise = shader.get_shader_parameter("ripples").noise slider.value = noise.frequency slider.value_changed.connect(func(x): noise.frequency = x ) elif param == "transition_dur": slider.value = params.transition_dur elif val != null: slider.value = val slider.value_changed.connect(func(x): shader.set_shader_parameter(param, x) ) slider.default_value = slider.value params[param] = slider.value slider.value_changed.connect(func(x): params[param] = x ) params_loaded.connect(func(): slider.value = params[param] ) button.pressed.connect(func(): slider.reset() ) params_reset.connect(func(): slider.reset() )