From 68cccc2a623cb9c030846e62868d813103bc65c1 Mon Sep 17 00:00:00 2001 From: ChaoticByte Date: Tue, 4 Jun 2024 18:31:04 +0200 Subject: [PATCH] Add project files --- .gitattributes | 2 + LICENSE | 2 +- icon.svg | 1 + icon.svg.import | 37 ++++++ project.godot | 58 ++++++++++ scenes/main.tscn | 153 +++++++++++++++++++++++++ src/Camera.gd | 48 ++++++++ src/Editor.gd | 135 ++++++++++++++++++++++ src/GlitchShader.gd | 10 ++ src/ImageViewport.gd | 11 ++ src/ImageViewportDisplays.gd | 9 ++ src/Main.gd | 39 +++++++ src/presets/Presets.gd | 11 ++ src/presets/shaders/empty.gdshader | 5 + src/presets/shaders/greyscale.gdshader | 10 ++ src/presets/shaders/lowpass.gdshader | 13 +++ src/ui_background.gdshader | 8 ++ 17 files changed, 551 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 icon.svg create mode 100644 icon.svg.import create mode 100644 project.godot create mode 100644 scenes/main.tscn create mode 100644 src/Camera.gd create mode 100644 src/Editor.gd create mode 100644 src/GlitchShader.gd create mode 100644 src/ImageViewport.gd create mode 100644 src/ImageViewportDisplays.gd create mode 100644 src/Main.gd create mode 100644 src/presets/Presets.gd create mode 100644 src/presets/shaders/empty.gdshader create mode 100644 src/presets/shaders/greyscale.gdshader create mode 100644 src/presets/shaders/lowpass.gdshader create mode 100644 src/ui_background.gdshader diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/LICENSE b/LICENSE index c06137c..920dc4f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Julian Müller +Copyright (c) 2024 Julian Müller (ChaoticByte) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..3fe4f4a --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..4f8973d --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bye3mkghgc0mg" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..49cb0f3 --- /dev/null +++ b/project.godot @@ -0,0 +1,58 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Glitch" +config/version="0.0.1s" +run/main_scene="res://scenes/main.tscn" +config/features=PackedStringArray("4.2", "Mobile") +run/low_processor_mode=true +config/icon="res://icon.svg" + +[autoload] + +ShaderPresets="*res://src/presets/Presets.gd" +GlitchShader="*res://src/GlitchShader.gd" + +[display] + +window/size/viewport_width=1280 +window/size/viewport_height=720 +window/energy_saving/keep_screen_on=false + +[editor_plugins] + +enabled=PackedStringArray() + +[input] + +zoom_out={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(244, 15),"global_position":Vector2(248, 56),"factor":1.0,"button_index":5,"canceled":false,"pressed":true,"double_click":false,"script":null) +] +} +zoom_in={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(270, 19),"global_position":Vector2(274, 60),"factor":1.0,"button_index":4,"canceled":false,"pressed":true,"double_click":false,"script":null) +] +} +drag={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(183, 23),"global_position":Vector2(187, 64),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null) +] +} + +[rendering] + +renderer/rendering_method="mobile" +textures/vram_compression/import_etc2_astc=true +textures/lossless_compression/force_png=true +environment/defaults/default_clear_color=Color(0, 0, 0, 1) diff --git a/scenes/main.tscn b/scenes/main.tscn new file mode 100644 index 0000000..20719fd --- /dev/null +++ b/scenes/main.tscn @@ -0,0 +1,153 @@ +[gd_scene load_steps=9 format=3 uid="uid://bjah7k4bxo044"] + +[ext_resource type="Script" path="res://src/Main.gd" id="1_2625y"] +[ext_resource type="Script" path="res://src/ImageViewport.gd" id="2_hvo65"] +[ext_resource type="Script" path="res://src/ImageViewportDisplays.gd" id="3_n4itb"] +[ext_resource type="Shader" path="res://src/ui_background.gdshader" id="4_ty3qx"] +[ext_resource type="Script" path="res://src/Editor.gd" id="7_g8bap"] +[ext_resource type="Script" path="res://src/Camera.gd" id="8_mls06"] + +[sub_resource type="ViewportTexture" id="ViewportTexture_lct1c"] +viewport_path = NodePath("ImageViewport") + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_onhxk"] +shader = ExtResource("4_ty3qx") + +[node name="Main" type="Node2D"] +script = ExtResource("1_2625y") + +[node name="ImageViewport" type="SubViewport" parent="."] +disable_3d = true +canvas_item_default_texture_filter = 0 +render_target_update_mode = 4 +script = ExtResource("2_hvo65") + +[node name="ImageSprite" type="Sprite2D" parent="ImageViewport"] + +[node name="ImageViewportDisplay" type="Sprite2D" parent="."] +texture = SubResource("ViewportTexture_lct1c") +script = ExtResource("3_n4itb") + +[node name="UI_Layer" type="CanvasLayer" parent="."] + +[node name="UserInterfaceContainer" type="Control" parent="UI_Layer"] +layout_mode = 3 +anchor_right = 0.225 +anchor_bottom = 1.0 +offset_right = 288.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Background" type="ColorRect" parent="UI_Layer/UserInterfaceContainer"] +material = SubResource("ShaderMaterial_onhxk") +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(1, 1, 1, 0) + +[node name="OpenFileDialog" type="FileDialog" parent="UI_Layer/UserInterfaceContainer"] +title = "Open a File" +size = Vector2i(521, 159) +ok_button_text = "Öffnen" +file_mode = 0 +access = 2 +use_native_dialog = true + +[node name="SaveFileDialog" type="FileDialog" parent="UI_Layer/UserInterfaceContainer"] +title = "Export Image" +size = Vector2i(661, 159) +ok_button_text = "Speichern" +access = 2 +filters = PackedStringArray("*.png") +use_native_dialog = true + +[node name="OpenImageButton" type="Button" parent="UI_Layer/UserInterfaceContainer"] +layout_mode = 0 +offset_left = 24.0 +offset_top = 24.0 +offset_right = 136.0 +offset_bottom = 56.0 +text = "Load Image" + +[node name="SaveImageButton" type="Button" parent="UI_Layer/UserInterfaceContainer"] +layout_mode = 0 +offset_left = 152.0 +offset_top = 24.0 +offset_right = 272.0 +offset_bottom = 56.0 +text = "Export Image" + +[node name="FitImageButton" type="Button" parent="UI_Layer/UserInterfaceContainer"] +layout_mode = 0 +offset_left = 288.0 +offset_top = 24.0 +offset_right = 376.0 +offset_bottom = 56.0 +text = "Fit Image" + +[node name="Editor" type="Control" parent="UI_Layer/UserInterfaceContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 24.0 +offset_top = 80.0 +offset_right = -24.0 +offset_bottom = -24.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("7_g8bap") + +[node name="Label" type="Label" parent="UI_Layer/UserInterfaceContainer/Editor"] +layout_mode = 0 +offset_top = 8.0 +offset_right = 104.0 +offset_bottom = 40.0 +text = "Load Preset: " +vertical_alignment = 1 + +[node name="PresetOptions" type="OptionButton" parent="UI_Layer/UserInterfaceContainer/Editor"] +layout_mode = 0 +offset_left = 104.0 +offset_top = 8.0 +offset_right = 240.0 +offset_bottom = 32.0 + +[node name="CodeEdit" type="CodeEdit" parent="UI_Layer/UserInterfaceContainer/Editor"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 48.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_font_sizes/font_size = 14 +placeholder_text = "// Test" +wrap_mode = 1 +minimap_draw = true +minimap_width = 40 +caret_blink = true +draw_control_chars = true +draw_tabs = true +draw_spaces = true +line_length_guidelines = Array[int]([80]) +gutters_draw_line_numbers = true +code_completion_enabled = true +indent_automatic = true +auto_brace_completion_enabled = true +auto_brace_completion_highlight_matching = true + +[node name="Camera" type="Camera2D" parent="."] +script = ExtResource("8_mls06") + +[connection signal="file_selected" from="UI_Layer/UserInterfaceContainer/OpenFileDialog" to="." method="_on_open_file_dialog_file_selected"] +[connection signal="file_selected" from="UI_Layer/UserInterfaceContainer/SaveFileDialog" to="." method="_on_save_file_dialog_file_selected"] +[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/OpenImageButton" to="." method="_on_open_image_button_pressed"] +[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/SaveImageButton" to="." method="_on_save_image_button_pressed"] +[connection signal="pressed" from="UI_Layer/UserInterfaceContainer/FitImageButton" to="Camera" method="_on_fit_image_button_pressed"] +[connection signal="item_selected" from="UI_Layer/UserInterfaceContainer/Editor/PresetOptions" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_preset_options_item_selected"] +[connection signal="code_completion_requested" from="UI_Layer/UserInterfaceContainer/Editor/CodeEdit" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_code_edit_code_completion_requested"] +[connection signal="text_changed" from="UI_Layer/UserInterfaceContainer/Editor/CodeEdit" to="UI_Layer/UserInterfaceContainer/Editor" method="_on_code_edit_text_changed"] diff --git a/src/Camera.gd b/src/Camera.gd new file mode 100644 index 0000000..e4036a7 --- /dev/null +++ b/src/Camera.gd @@ -0,0 +1,48 @@ +extends Camera2D + +var drag = false +var _freeze = false + +@onready var user_interface_container = get_parent().get_node("UI_Layer/UserInterfaceContainer") +@onready var image_viewport = get_parent().get_node("ImageViewport") + +func _input(event): + if event.is_action_pressed("zoom_out") && !_freeze: + zoom_out() + elif event.is_action_pressed("zoom_in") && !_freeze: + zoom_in() + if event.is_action_pressed("drag") && !_freeze: + drag = true + elif event.is_action_released("drag"): + drag = false + if drag && event is InputEventMouseMotion: + global_position -= event.relative / zoom + +func fit_image(): + var ui_container_size = user_interface_container.size + var image_size = image_viewport.image_original.get_size() + var viewport_size = get_viewport_rect().size + var zoomf = (viewport_size.x - ui_container_size.x) / image_size.x / 1.1 + if zoomf * image_size.y > viewport_size.y: + zoomf = viewport_size.y / image_size.y / 1.1 + zoom = Vector2(zoomf, zoomf) + global_position = Vector2(-((ui_container_size.x) / 2 / zoom.x), 0) + +func zoom_in(): + var old_mouse_pos = get_global_mouse_position() + zoom *= 1.2 + global_position += old_mouse_pos - get_global_mouse_position() + +func zoom_out(): + var old_mouse_pos = get_global_mouse_position() + zoom *= 1/1.2 + global_position += old_mouse_pos - get_global_mouse_position() + +func freeze(): + _freeze = true + +func unfreeze(): + _freeze = false + +func _on_fit_image_button_pressed(): + fit_image() diff --git a/src/Editor.gd b/src/Editor.gd new file mode 100644 index 0000000..c1a84d8 --- /dev/null +++ b/src/Editor.gd @@ -0,0 +1,135 @@ +extends Control + +@onready var preset_options = $PresetOptions +@onready var code_editor = $CodeEdit + +@onready var camera_freeze = get_parent().get_parent().get_parent().find_child("Camera").freeze +@onready var camera_unfreeze = get_parent().get_parent().get_parent().find_child("Camera").unfreeze + +var selected_preset_name = ShaderPresets.default_preset + +# + +const gdshader_datatypes = [ + "in", "out", "inout", + "varying", "uniform", + "const", "lowp", "mediump", "heighp", + "void", + "bool", "bvec2", "bvec3", "bvec4", + "int", "ivec2", "ivec3", "ivec4", + "uint", "uvec2", "uvec3", "uvec4", + "float", "vec2", "vec3", "vec4", + "mat2", "mat3", "mat4", + "sample2D", "isampler2D", "usample2D", + "sampler2DArray", "isample2DArray", "usample2DArray", + "sample3D", "isampler3D", "usample3D", + "samplerCube", "sampleCubeArray" +] + +const gdshader_builtins = [ + "TIME", "PI", "TAU", "E", + "MODEL_MATRIX", + "CANVAS_MATRIX", + "SCREEN_MATRIX", + "INSTANCE_ID", + "INSTANCE_CUSTOM", + "AT_LIGHT_PASS", + "TEXTURE_PIXEL_SIZE", + "VERTEX", + "VERTEX_ID", + "UV", + "COLOR", + "POINT_SIZE", + "FRAGCOORD", + "SCREEN_PIXEL_SIZE", + "POINT_COORD", + "TEXTURE", + "TEXTURE_PIXEL_SIZE", + "SPECULAR_SHININESS_TEXTURE", + "SPECULAR_SHININESS", + "UV", + "SCREEN_UV", + "SCREEN_TEXTURE", + "NORMAL", + "NORMAL_TEXTURE", + "NORMAL_MAP", + "NORMAL_MAP_DEPTH", + "SHADOW_VERTEX", + "LIGHT_VERTEX" +] + +const gdshader_flow_control = [ + "if", "else", + "for", + "do", "while", + "switch", "case", + "break", + "return" +] + +class ShaderSyntaxHighlighter extends CodeHighlighter: + func _init(): + add_color_region("//", "", Color.WEB_GRAY, true) + add_color_region("/*", "*/", Color.WEB_GRAY, false) + function_color = Color.INDIAN_RED + keyword_colors = { + "shader_type": Color.ORCHID + } + for dt in gdshader_datatypes: + keyword_colors[dt] = Color.INDIAN_RED + for bi in gdshader_builtins: + keyword_colors[bi] = Color.DARK_TURQUOISE + for fc in gdshader_flow_control: + keyword_colors[fc] = Color.CORAL + member_variable_color = Color.LIGHT_BLUE + number_color = Color.AQUA + symbol_color = Color.GRAY + +func _on_code_edit_code_completion_requested(): + for dt in gdshader_datatypes: + code_editor.code_completion_prefixes.append(dt) + code_editor.add_code_completion_option(CodeEdit.KIND_CLASS, dt, dt, Color.INDIAN_RED) + for bi in gdshader_builtins: + code_editor.code_completion_prefixes.append(bi) + code_editor.add_code_completion_option(CodeEdit.KIND_VARIABLE, bi, bi, Color.DARK_TURQUOISE) + for fc in gdshader_flow_control: + code_editor.code_completion_prefixes.append(fc) + code_editor.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, fc, fc, Color.DARK_TURQUOISE) + code_editor.update_code_completion_options(true) + +# + +func _ready(): + code_editor.code_completion_enabled = true + code_editor.syntax_highlighter = ShaderSyntaxHighlighter.new() + for c in get_children(): + c.connect("mouse_entered", camera_freeze) + c.connect("mouse_exited", camera_unfreeze) + update() + +func _on_code_edit_text_changed(): + var shader = Shader.new() + shader.code = code_editor.text + code_editor.request_code_completion() + GlitchShader.shader = shader + GlitchShader.apply() + +func _on_preset_options_item_selected(index): + selected_preset_name = preset_options.get_item_text(index) + GlitchShader.shader = ShaderPresets.presets[selected_preset_name] + GlitchShader.apply() + update() + +func update(): + preset_options.clear() + # the following lines are weird af + var presets: Array[String] = [] + var current_p_idx = 0 + for p in ShaderPresets.presets: + presets.append(p) + if p == selected_preset_name: + current_p_idx = len(presets) - 1 + preset_options.add_item(p) + preset_options.select(current_p_idx) + # weirdness ends here + code_editor.text = GlitchShader.shader.code diff --git a/src/GlitchShader.gd b/src/GlitchShader.gd new file mode 100644 index 0000000..13d7692 --- /dev/null +++ b/src/GlitchShader.gd @@ -0,0 +1,10 @@ +extends Node + +var target_sprite: Sprite2D + +@onready var shader: Shader = ShaderPresets.presets[ShaderPresets.default_preset] + +func apply(): + var mat = ShaderMaterial.new() + mat.shader = shader + target_sprite.material = mat diff --git a/src/ImageViewport.gd b/src/ImageViewport.gd new file mode 100644 index 0000000..eb74dee --- /dev/null +++ b/src/ImageViewport.gd @@ -0,0 +1,11 @@ +extends SubViewport + +@onready var image_sprite = $ImageSprite + +var image_original: ImageTexture + +func set_original_image(image: Image): + image_original = ImageTexture.create_from_image(image) + image_sprite.texture = image_original + image_sprite.offset = image_original.get_size() / 2 + size = image_original.get_size() diff --git a/src/ImageViewportDisplays.gd b/src/ImageViewportDisplays.gd new file mode 100644 index 0000000..d4817ca --- /dev/null +++ b/src/ImageViewportDisplays.gd @@ -0,0 +1,9 @@ +extends Sprite2D + +@onready var camera = get_parent().get_node("Camera") + +func _process(_delta): + if camera.zoom.x >= 1.5: + texture_filter = TEXTURE_FILTER_NEAREST_WITH_MIPMAPS + else: + texture_filter = TEXTURE_FILTER_LINEAR diff --git a/src/Main.gd b/src/Main.gd new file mode 100644 index 0000000..3ed00ae --- /dev/null +++ b/src/Main.gd @@ -0,0 +1,39 @@ +extends Node2D + +@onready var camera = $Camera +@onready var image_viewport = $ImageViewport +@onready var image_sprite = $ImageViewport/ImageSprite +@onready var ui_container = $UI_Layer/UserInterfaceContainer +@onready var ui_control_fileopen = $UI_Layer/UserInterfaceContainer/OpenFileDialog +@onready var ui_control_filesave = $UI_Layer/UserInterfaceContainer/SaveFileDialog + +func _ready(): + GlitchShader.target_sprite = image_sprite + GlitchShader.shader = ShaderPresets.presets[ShaderPresets.default_preset] + +func _on_open_image_button_pressed(): + if OS.get_name() == "Android": + Engine.get_singleton("GodotGetImage").getGalleryImage() + else: + ui_control_fileopen.show() + +func _on_open_file_dialog_file_selected(path): + var img = Image.new() + var err = img.load(path) + if err == OK: + image_viewport.set_original_image(img) + GlitchShader.apply() + camera.fit_image() + else: + print("An error occured!") + +func _on_save_image_button_pressed(): + ui_control_filesave.show() + +func _on_save_file_dialog_file_selected(path): + # Get viewport texture + await RenderingServer.frame_post_draw # for good measure + var img = image_viewport.get_texture().get_image() + var err = img.save_png(path) + if err != OK: + print("An error occured!") diff --git a/src/presets/Presets.gd b/src/presets/Presets.gd new file mode 100644 index 0000000..eccd3d6 --- /dev/null +++ b/src/presets/Presets.gd @@ -0,0 +1,11 @@ +extends Node + +const dir = "res://src/presets/shaders/" + +@onready var presets = { + "Empty": load(dir + "empty.gdshader"), + "Greyscale": load(dir + "greyscale.gdshader"), + "Lowpass": load(dir + "lowpass.gdshader") +} + +var default_preset: String = "Empty" diff --git a/src/presets/shaders/empty.gdshader b/src/presets/shaders/empty.gdshader new file mode 100644 index 0000000..0cb1281 --- /dev/null +++ b/src/presets/shaders/empty.gdshader @@ -0,0 +1,5 @@ +shader_type canvas_item; + +void fragment() { + // Called for every pixel the material is visible on. +} diff --git a/src/presets/shaders/greyscale.gdshader b/src/presets/shaders/greyscale.gdshader new file mode 100644 index 0000000..2c0f19d --- /dev/null +++ b/src/presets/shaders/greyscale.gdshader @@ -0,0 +1,10 @@ +shader_type canvas_item; + +void fragment() { + // TODO: not only r + vec4 tex = texture(TEXTURE , UV); + COLOR.r = tex.r; + COLOR.g = tex.r; + COLOR.b = tex.r; + COLOR.a = tex.a; +} diff --git a/src/presets/shaders/lowpass.gdshader b/src/presets/shaders/lowpass.gdshader new file mode 100644 index 0000000..9dc44f7 --- /dev/null +++ b/src/presets/shaders/lowpass.gdshader @@ -0,0 +1,13 @@ +shader_type canvas_item; + +// Settings +const float threshold = 0.5; +// + +void fragment() { + vec4 tex = texture(TEXTURE , UV); + COLOR.r = min(tex.r, threshold); + COLOR.g = min(tex.g, threshold); + COLOR.b = min(tex.b, threshold); + COLOR.a = tex.a; +} diff --git a/src/ui_background.gdshader b/src/ui_background.gdshader new file mode 100644 index 0000000..9df8052 --- /dev/null +++ b/src/ui_background.gdshader @@ -0,0 +1,8 @@ +shader_type canvas_item; + +uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, repeat_disable, filter_linear_mipmap_anisotropic; + +void fragment() { + COLOR.rgb = clamp(textureLod(SCREEN_TEXTURE, SCREEN_UV, 10.0).rgb, 0.05, 0.7); + COLOR.a = 1.0; +}