diff --git a/docs/docs/postprocess.md b/docs/docs/postprocess.md new file mode 100644 index 0000000..5f7f7cc --- /dev/null +++ b/docs/docs/postprocess.md @@ -0,0 +1,236 @@ +--- +sidebar_position: 5 +--- + +# Postprocess + +The `` tag in Gurted allows you to apply real-time visual effects to your entire webpage through GPU-accelerated shaders. These effects are rendered as an overlay on top of your content, not affecting the browser UI. + +## Usage + +The postprocess tag supports three ways to define shader effects: + +```html + + + + + + + + +shader_type canvas_item; +void fragment() { + COLOR = texture(SCREEN_TEXTURE, SCREEN_UV); +} + +``` + +## Shader Tutorial +For documentation on how to write GDShader code, see the [Godot Shader Language documentation](https://docs.godotengine.org/en/stable/tutorials/shading/index.html). + +### Parameters + +HTML attributes are automatically converted to shader uniforms with the following supported types: + +#### Numeric Types +```html + + + + + + + + +``` + +#### Vector Types +```html + + + + + + + + + + + +``` + +#### Color Values +```html + + + + + +``` + +## Built-in Preset Shaders + +### CRT Monitor Effect +Creates a retro CRT monitor appearance with scanlines, distortion, and screen curvature. + +```html + +``` + +![CRT effect](../static/img/docs/crt.gif) + +**Available Properties:** +- `curvature` (0.0-10.0, default: 2.0) - Screen curvature amount +- `skip` (0.0-1.0, default: 1.0) - Vertical hold distortion intensity +- `image_flicker` (0.0-1.0, default: 1.0) - Image flicker intensity +- `vignette_flicker_speed` (0.0-2.0, default: 1.0) - Vignette animation speed +- `vignette_strength` (0.0-2.0, default: 1.0) - Dark edge vignette intensity +- `small_scanlines_speed` (0.0-10.0, default: 1.0) - Fine scanline animation speed +- `small_scanlines_proximity` (0.01-2.0, default: 1.0) - Fine scanline density +- `small_scanlines_opacity` (0.01-5.0, default: 1.0) - Fine scanline visibility +- `scanlines_opacity` (0.0-2.0, default: 1.0) - Main scanline visibility +- `scanlines_speed` (0.0-5.0, default: 1.0) - Main scanline animation speed +- `scanline_thickness` (0.0-0.6, default: 0.5) - Scanline thickness +- `scanlines_spacing` (0.3-3.0, default: 1.0) - Space between scanlines + +### Film Grain Effect +Adds vintage film grain noise to give content an analog film appearance. + +```html + +``` + +![Film grain effect](../static/img/docs/film.png) + +**Available Properties:** +- `grain_amount` (0.0-1.0, default: 0.05) - Amount of grain noise added +- `grain_size` (0.1-10.0, default: 1.0) - Size/scale of individual grain particles + +### Vignette Effect +Creates a darkened border around the screen edges, focusing attention on the center. + +```html + +``` +![Vignette effect](../static/img/docs/vignette.png) + +**Available Properties:** +- `inner_radius` (0.0-1.0, default: 0.1) - Inner edge of the vignette effect +- `outer_radius` (0.0-1.0, default: 1.0) - Outer edge where vignette is strongest +- `vignette_strength` (0.0-2.0, default: 1.0) - Intensity of the darkening effect +- `dither_strength` (0.0-1.0, default: 0.03) - Noise added to prevent banding +- `vignette_color` (color, default: black) - Color of the vignette overlay + +### Pencil Effect +Converts the webpage into a pencil drawing style with adjustable thresholds for line detection. + +```html + +``` + +![Pencil effect](../static/img/docs/pencil.png) + +**Available Properties:** +- `u_bgColorFactor` (0.0-1.0, default: 0.4) - Blend amount of background color +- `u_threshold1` (0.0-1.0, default: 0.75) - Brightest areas threshold +- `u_threshold2` (0.0-1.0, default: 0.50) - Medium-bright areas threshold +- `u_threshold3` (0.0-1.0, default: 0.25) - Medium-dark areas threshold +- `u_threshold4` (0.0-1.0, default: 0.05) - Darkest areas threshold +- `u_bgTiling` (Vector2, default: vec2(1.0, 1.0)) - Background texture tiling +- `u_patternTiling` (Vector2, default: vec2(1.0, 1.0)) - Pattern texture tiling +- `u_bgColor` (color, default: white) - Background paper color +- `u_patternColor` (color, default: black) - Pencil line color + +### Snowfall Effect +Adds animated falling snow particles over the content with customizable layers and physics. + +```html + +``` + +![Snowfall effect](../static/img/docs/snowfall.gif) + +**Available Properties:** +- `spread` (0.0-1.5, default: 0.5) - Horizontal spread of snowflakes +- `size` (0.01-5.0, default: 0.5) - Size of individual snowflakes +- `snow_color` (color, default: white) - Color of the snow particles +- `snow_transparency` (-0.5-1.0, default: 0.2) - Transparency of snow overlay +- `speed` (0.0-10.0, default: 0.5) - Falling speed of snowflakes +- `wind` (-2.0-2.0, default: 0.0) - Horizontal wind effect +- `num_of_layers` (integer, default: 40) - Number of snow layers for depth + +### Chromatic Aberration Effect +Simulates lens distortion by separating RGB color channels, creating a retro video glitch effect. + +```html + +``` + +![Chrome effect](../static/img/docs/chrome.png) + +**Available Properties:** +- `levels` (integer, default: 3) - Number of color separation levels +- `spread` (float, default: 0.01) - Amount of color channel separation + + +### Radial Blur Effect +Creates motion blur radiating from a center point, useful for speed effects or focus attention. + +```html + +``` + +![Radial blur effect](../static/img/docs/rblur.png) + +**Available Properties:** +- `blur_center` (Vector2, default: vec2(0.5, 0.5)) - Center point of the blur effect +- `blur_power` (0.0-1.0, default: 0.01) - Intensity of the blur effect +- `sampling_count` (1-64, default: 2) - Quality of the blur (higher = smoother) + +### Lens Flare Effect +Adds realistic lens flare effects, simulating light hitting a camera lens. + +```html + +``` +![Lensflare effect](../static/img/docs/lensflare.png) + +**Available Properties:** +- `sun_position` (Vector2, default: vec2(400.0, 0.0)) - Position of the light source +- `tint` (Vector3, default: vec3(1.4, 1.2, 1.0)) - Color tint of the lens flare + +### Foliage Sway Effect +Creates animated wave distortion effects, mimicking vegetation movement or underwater effects. + +```html + +``` + +![Foliage effect](../static/img/docs/foliage.gif) + +**Available Properties:** +- `x_intensity` (float, default: 3.0) - Horizontal sway intensity +- `y_intensity` (float, default: 0.5) - Vertical sway intensity +- `offset` (float, default: 0.0) - Animation offset for timing +- `speed` (0-20, default: 2.0) - Animation speed +- `wave_frequency` (0-100, default: 20) - Frequency of wave oscillations +- `wave_length` (50-800, default: 200.0) - Length of wave patterns + +### Dithering Effect +Applies retro pixel art dithering with color palette reduction for a vintage gaming aesthetic. + +```html + +``` + +![Dither effect](../static/img/docs/dither.png) + +:::note +Due to the limitations of GDShader, the dithering effect relies on a `GradientTexture` node internally. This means the colors are hardcoded to be a rusty tint - unchangeable via parameters. A similar effect can be achieved with a custom `` shader without external nodes - however, that's beyond the scope of this preset. +::: + +**Available Properties:** +- `pixel` (float, default: 1.0) - Pixel size for the dithering pattern + +All postprocess shaders are GPU-accelerated thanks to Godot's shader system. diff --git a/docs/sidebars.ts b/docs/sidebars.ts index e73decf..8ccef5d 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -31,7 +31,6 @@ const sidebars: SidebarsConfig = { items: [ 'dns-system', 'flumi-browser', - 'search-engine' ], }, { @@ -40,6 +39,7 @@ const sidebars: SidebarsConfig = { items: [ 'html', 'css', + 'postprocess', ], }, ], diff --git a/docs/static/img/docs/chrome.png b/docs/static/img/docs/chrome.png new file mode 100644 index 0000000..b980a58 Binary files /dev/null and b/docs/static/img/docs/chrome.png differ diff --git a/docs/static/img/docs/crt.gif b/docs/static/img/docs/crt.gif new file mode 100644 index 0000000..1fe9291 Binary files /dev/null and b/docs/static/img/docs/crt.gif differ diff --git a/docs/static/img/docs/dither.png b/docs/static/img/docs/dither.png new file mode 100644 index 0000000..d40c177 Binary files /dev/null and b/docs/static/img/docs/dither.png differ diff --git a/docs/static/img/docs/film.png b/docs/static/img/docs/film.png new file mode 100644 index 0000000..a35f61c Binary files /dev/null and b/docs/static/img/docs/film.png differ diff --git a/docs/static/img/docs/foliage.gif b/docs/static/img/docs/foliage.gif new file mode 100644 index 0000000..c843a94 Binary files /dev/null and b/docs/static/img/docs/foliage.gif differ diff --git a/docs/static/img/docs/lensflare.png b/docs/static/img/docs/lensflare.png new file mode 100644 index 0000000..50a3028 Binary files /dev/null and b/docs/static/img/docs/lensflare.png differ diff --git a/docs/static/img/docs/pencil.png b/docs/static/img/docs/pencil.png new file mode 100644 index 0000000..b08615f Binary files /dev/null and b/docs/static/img/docs/pencil.png differ diff --git a/docs/static/img/docs/rblur.png b/docs/static/img/docs/rblur.png new file mode 100644 index 0000000..03e3c3f Binary files /dev/null and b/docs/static/img/docs/rblur.png differ diff --git a/docs/static/img/docs/snowfall.gif b/docs/static/img/docs/snowfall.gif new file mode 100644 index 0000000..76e3b20 Binary files /dev/null and b/docs/static/img/docs/snowfall.gif differ diff --git a/docs/static/img/docs/vignette.png b/docs/static/img/docs/vignette.png new file mode 100644 index 0000000..77d082b Binary files /dev/null and b/docs/static/img/docs/vignette.png differ diff --git a/flumi/Assets/Textures/bayer8tile4.png b/flumi/Assets/Textures/bayer8tile4.png new file mode 100644 index 0000000..3eef319 Binary files /dev/null and b/flumi/Assets/Textures/bayer8tile4.png differ diff --git a/flumi/Assets/Textures/bayer8tile4.png.import b/flumi/Assets/Textures/bayer8tile4.png.import new file mode 100644 index 0000000..0abd724 --- /dev/null +++ b/flumi/Assets/Textures/bayer8tile4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8eervlu44g5e" +path="res://.godot/imported/bayer8tile4.png-af05367272eb1e9c5c1494aea351d772.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Textures/bayer8tile4.png" +dest_files=["res://.godot/imported/bayer8tile4.png-af05367272eb1e9c5c1494aea351d772.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=0 diff --git a/flumi/Assets/Textures/blue_noise.png b/flumi/Assets/Textures/blue_noise.png new file mode 100644 index 0000000..ac78acc Binary files /dev/null and b/flumi/Assets/Textures/blue_noise.png differ diff --git a/flumi/Assets/Textures/blue_noise.png.import b/flumi/Assets/Textures/blue_noise.png.import new file mode 100644 index 0000000..37a1db8 --- /dev/null +++ b/flumi/Assets/Textures/blue_noise.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bh6ou8qfqhml3" +path="res://.godot/imported/blue_noise.png-3429c5fff13cc3510f3a6adb3d9b290a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Textures/blue_noise.png" +dest_files=["res://.godot/imported/blue_noise.png-3429c5fff13cc3510f3a6adb3d9b290a.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 diff --git a/flumi/Assets/Textures/dither_matrix.png b/flumi/Assets/Textures/dither_matrix.png new file mode 100644 index 0000000..3005541 Binary files /dev/null and b/flumi/Assets/Textures/dither_matrix.png differ diff --git a/flumi/Assets/Textures/dither_matrix.png.import b/flumi/Assets/Textures/dither_matrix.png.import new file mode 100644 index 0000000..e2faf22 --- /dev/null +++ b/flumi/Assets/Textures/dither_matrix.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crdyaxcy0l5fe" +path="res://.godot/imported/dither_matrix.png-e5f72ab3b733bd12bb9be69cb29c5303.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Textures/dither_matrix.png" +dest_files=["res://.godot/imported/dither_matrix.png-e5f72ab3b733bd12bb9be69cb29c5303.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 diff --git a/flumi/Assets/Textures/parchment.jpg b/flumi/Assets/Textures/parchment.jpg new file mode 100644 index 0000000..a0544b4 Binary files /dev/null and b/flumi/Assets/Textures/parchment.jpg differ diff --git a/flumi/Assets/Textures/parchment.jpg.import b/flumi/Assets/Textures/parchment.jpg.import new file mode 100644 index 0000000..a8b2019 --- /dev/null +++ b/flumi/Assets/Textures/parchment.jpg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8x712hkjbsh" +path="res://.godot/imported/parchment.jpg-ea29c24066df61d46bc7b0bcc25a86c1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Textures/parchment.jpg" +dest_files=["res://.godot/imported/parchment.jpg-ea29c24066df61d46bc7b0bcc25a86c1.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 diff --git a/flumi/Assets/Textures/pencil.jpg b/flumi/Assets/Textures/pencil.jpg new file mode 100644 index 0000000..68a5f94 Binary files /dev/null and b/flumi/Assets/Textures/pencil.jpg differ diff --git a/flumi/Assets/Textures/pencil.jpg.import b/flumi/Assets/Textures/pencil.jpg.import new file mode 100644 index 0000000..a64b16a --- /dev/null +++ b/flumi/Assets/Textures/pencil.jpg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dnvdbk47n56ej" +path="res://.godot/imported/pencil.jpg-3bb1b8082faf74808f54e9dd81d1b7d0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Textures/pencil.jpg" +dest_files=["res://.godot/imported/pencil.jpg-3bb1b8082faf74808f54e9dd81d1b7d0.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 diff --git a/flumi/Scenes/Tags/postprocess.tscn b/flumi/Scenes/Tags/postprocess.tscn new file mode 100644 index 0000000..cd6240d --- /dev/null +++ b/flumi/Scenes/Tags/postprocess.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://bpn7d4x5qr8vw"] + +[ext_resource type="Script" path="res://Scripts/Tags/postprocess.gd" id="1_postprocess"] + +[node name="postprocess" type="Control"] +script = ExtResource("1_postprocess") \ No newline at end of file diff --git a/flumi/Scripts/B9/HTMLParser.gd b/flumi/Scripts/B9/HTMLParser.gd index 645fbb6..ad06129 100644 --- a/flumi/Scripts/B9/HTMLParser.gd +++ b/flumi/Scripts/B9/HTMLParser.gd @@ -430,6 +430,9 @@ func get_all_images() -> Array[String]: func get_all_scripts() -> Array[String]: return get_attribute_values("script", "src") +func get_all_postprocess() -> Array[String]: + return get_attribute_values("postprocess", "src") + func process_scripts(lua_api: LuaAPI, _lua_vm) -> void: if not lua_api: print("Warning: Lua API not available for script processing") @@ -459,6 +462,14 @@ func process_external_scripts(lua_api: LuaAPI, _lua_vm, base_url: String = "") - if not script_content.is_empty(): lua_api.execute_lua_script(script_content) +func process_postprocess() -> HTMLParser.HTMLElement: + var postprocess_elements = find_all("postprocess") + if postprocess_elements.is_empty(): + return null + + # Return the last postprocess element (last defined wins) + return postprocess_elements[-1] + func get_all_stylesheets() -> Array[String]: return get_attribute_values("style", "src") diff --git a/flumi/Scripts/B9/Lua.gd b/flumi/Scripts/B9/Lua.gd index 884bf75..90f80cc 100644 --- a/flumi/Scripts/B9/Lua.gd +++ b/flumi/Scripts/B9/Lua.gd @@ -672,7 +672,7 @@ func _handle_dom_operation(operation: Dictionary): "get_text": _handle_text_getting(operation) "append_element": - LuaDOMUtils.handle_element_append(operation, dom_parser, self) + LuaDOMUtils.handle_element_append(operation, dom_parser) "add_class": LuaClassListUtils.handle_add_class(operation, dom_parser) "remove_class": @@ -682,7 +682,7 @@ func _handle_dom_operation(operation: Dictionary): "remove_element": LuaDOMUtils.handle_element_remove(operation, dom_parser) "insert_before": - LuaDOMUtils.handle_insert_before(operation, dom_parser, self) + LuaDOMUtils.handle_insert_before(operation, dom_parser) "insert_after": LuaDOMUtils.handle_insert_after(operation, dom_parser) "replace_child": diff --git a/flumi/Scripts/GurtProtocol.gd b/flumi/Scripts/GurtProtocol.gd index 2500cea..6df9a3f 100644 --- a/flumi/Scripts/GurtProtocol.gd +++ b/flumi/Scripts/GurtProtocol.gd @@ -9,7 +9,9 @@ static func is_gurt_domain(url: String) -> bool: return true if not url.contains("://"): - var parts = url.split(".") + # Extract just the domain part (before any path) + var domain = url.split("/")[0] + var parts = domain.split(".") return parts.size() == 2 return false diff --git a/flumi/Scripts/StyleManager.gd b/flumi/Scripts/StyleManager.gd index 01880bf..d43ec6c 100644 --- a/flumi/Scripts/StyleManager.gd +++ b/flumi/Scripts/StyleManager.gd @@ -64,19 +64,33 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement, if (width != null or height != null) and not skip_sizing: if width != null: - if width is String and width == "100%": - node.size_flags_horizontal = Control.SIZE_EXPAND_FILL - node.custom_minimum_size.x = 0 + if width is String and width.ends_with("%"): + if width == "100%": + node.size_flags_horizontal = Control.SIZE_EXPAND_FILL + node.custom_minimum_size.x = 0 + else: + # For other percentages, convert to viewport-relative size + var percent = float(width.replace("%", "")) / 100.0 + var viewport_width = node.get_viewport().get_visible_rect().size.x if node.get_viewport() else 800 + node.custom_minimum_size.x = viewport_width * percent node.set_meta("size_flags_set_by_style_manager", true) + node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN else: node.custom_minimum_size.x = width node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN if height != null: - if height is String and height == "100%": - node.size_flags_vertical = Control.SIZE_EXPAND_FILL - node.custom_minimum_size.y = 0 + if height is String and height.ends_with("%"): + if height == "100%": + node.size_flags_vertical = Control.SIZE_EXPAND_FILL + node.custom_minimum_size.y = 0 + else: + # For other percentages, convert to viewport-relative size + var percent = float(height.replace("%", "")) / 100.0 + var viewport_height = node.get_viewport().get_visible_rect().size.y if node.get_viewport() else 600 + node.custom_minimum_size.y = viewport_height * percent node.set_meta("size_flags_set_by_style_manager", true) + node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN else: node.custom_minimum_size.y = height node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN diff --git a/flumi/Scripts/TabContainer.gd b/flumi/Scripts/TabContainer.gd index 397ca70..c647d80 100644 --- a/flumi/Scripts/TabContainer.gd +++ b/flumi/Scripts/TabContainer.gd @@ -210,7 +210,9 @@ func create_tab() -> void: var index = tabs.size(); var tab = TAB.instantiate() tabs.append(tab) + h_box_container.add_child(tab) tab.tab_pressed.connect(_tab_pressed.bind(index)) + tab.tab_closed.connect(_tab_closed.bind(index)) var viewport_width = get_viewport().get_visible_rect().size.x var available_width = viewport_width - POPUP_BUTTON_WIDTH - NEW_TAB_BUTTON_WIDTH - OTHER_UI_PADDING var visible_count = calculate_visible_tab_count(available_width) diff --git a/flumi/Scripts/Tags/postprocess.gd b/flumi/Scripts/Tags/postprocess.gd new file mode 100644 index 0000000..d16de94 --- /dev/null +++ b/flumi/Scripts/Tags/postprocess.gd @@ -0,0 +1,162 @@ +class_name HTMLPostprocess +extends Control + +const Network = preload("res://Scripts/Network.gd") + +var element: HTMLParser.HTMLElement +var parser: HTMLParser +var shader_material: ShaderMaterial +var built_in_shaders = { + "crt": "res://Shaders/crt.gdshader", + "film": "res://Shaders/film.gdshader", + "vignette": "res://Shaders/vignette.gdshader", + "pencil": "res://Shaders/pencil.gdshader", + "snowfall": "res://Shaders/snowfall.gdshader", + "chrome": "res://Shaders/chrome.gdshader", + "rblur": "res://Shaders/rblur.gdshader", + "lensflare": "res://Shaders/lensflare.gdshader", + "foliage": "res://Shaders/foliage.gdshader", + "dither": "res://Shaders/dither.gdshader" +} + +func init(element_: HTMLParser.HTMLElement, parser_: HTMLParser): + element = element_ + parser = parser_ + + var preset = element.get_attribute("preset") + if preset and built_in_shaders.has(preset): + await apply_preset_shader(preset) + + elif element.has_attribute("src"): + await load_external_shader() + + elif not element.text_content.is_empty(): + apply_inline_shader() + +func apply_preset_shader(preset_name: String): + var shader_resource = built_in_shaders[preset_name] + var shader = load(shader_resource) + + shader_material = ShaderMaterial.new() + shader_material.shader = shader + + shader_material.set_shader_parameter("u_bgTexture", load("res://Assets/Textures/parchment.jpg")) + shader_material.set_shader_parameter("u_patternTexture", load("res://Assets/Textures/pencil.jpg")) + + var BLUE_NOISE = load("res://Assets/Textures/blue_noise.png") + shader_material.set_shader_parameter("uTexBlueNoise", BLUE_NOISE) + var gradient_texture = GradientTexture2D.new() + var gradient = Gradient.new() + gradient.colors = [Color("#8B4513"), Color("#CD853F"), Color("#D2691E"), Color("#B22222"), Color("#A0522D")] + gradient_texture.gradient = gradient + shader_material.set_shader_parameter("pallete", gradient_texture) + + apply_shader_uniforms() + apply_postprocessing_to_viewport() + +func load_external_shader(): + var src = element.get_attribute("src") + + var main = Engine.get_main_loop().current_scene + var resolved_url = URLUtils.resolve_url(main.current_domain, src) + + var network = Network.new() + var response = await network.fetch_content(resolved_url) + + if response.success: + var shader_code = response.content.get_string_from_utf8() + var shader = Shader.new() + shader.code = shader_code + + shader_material = ShaderMaterial.new() + shader_material.shader = shader + + apply_shader_uniforms() + apply_postprocessing_to_viewport() + else: + print("Failed to load shader from: ", resolved_url) + +func apply_inline_shader(): + var shader_code = element.text_content.strip_edges() + if shader_code.is_empty(): + return + + var shader = Shader.new() + shader.code = shader_code + + shader_material = ShaderMaterial.new() + shader_material.shader = shader + + apply_shader_uniforms() + apply_postprocessing_to_viewport() + +func apply_shader_uniforms(): + if not shader_material or not shader_material.shader: + return + + for attr_name in element.attributes: + if attr_name in ["src", "preset"]: + continue + + var attr_value = element.get_attribute(attr_name) + var uniform_value = parse_uniform_value(attr_value) + + if uniform_value != null: + shader_material.set_shader_parameter(attr_name, uniform_value) + +func parse_uniform_value(value_string: String): + if value_string.is_valid_float(): + return value_string.to_float() + + if value_string.is_valid_int(): + return value_string.to_int() + + if value_string.to_lower() == "true": + return true + elif value_string.to_lower() == "false": + return false + + if value_string.begins_with("Vector2(") or value_string.begins_with("vec2("): + var vec_str = value_string.replace("Vector2(", "").replace("vec2(", "").replace(")", "") + var components = vec_str.split(",") + if components.size() == 2: + return Vector2(components[0].strip_edges().to_float(), components[1].strip_edges().to_float()) + + if value_string.begins_with("Vector3(") or value_string.begins_with("vec3("): + var vec_str = value_string.replace("Vector3(", "").replace("vec3(", "").replace(")", "") + var components = vec_str.split(",") + if components.size() == 3: + return Vector3(components[0].strip_edges().to_float(), components[1].strip_edges().to_float(), components[2].strip_edges().to_float()) + + if value_string.begins_with("Vector4(") or value_string.begins_with("vec4("): + var vec_str = value_string.replace("Vector4(", "").replace("vec4(", "").replace(")", "") + var components = vec_str.split(",") + if components.size() == 4: + return Vector4(components[0].strip_edges().to_float(), components[1].strip_edges().to_float(), components[2].strip_edges().to_float(), components[3].strip_edges().to_float()) + + if value_string.begins_with("#"): + return Color(value_string) + + return value_string + +func apply_postprocessing_to_viewport(): + if not shader_material: + return + + var main_scene = Engine.get_main_loop().current_scene + var active_tab = main_scene.get_active_tab() + var panel_container = active_tab.background_panel + + var existing_overlay = panel_container.get_node_or_null("PostprocessOverlay") + if existing_overlay: + existing_overlay.queue_free() + + var overlay_rect = ColorRect.new() + overlay_rect.name = "PostprocessOverlay" + overlay_rect.material = shader_material + overlay_rect.color = Color.WHITE + overlay_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE + overlay_rect.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + overlay_rect.z_index = 100 + + panel_container.add_child(overlay_rect) diff --git a/flumi/Scripts/Tags/postprocess.gd.uid b/flumi/Scripts/Tags/postprocess.gd.uid new file mode 100644 index 0000000..9846766 --- /dev/null +++ b/flumi/Scripts/Tags/postprocess.gd.uid @@ -0,0 +1 @@ +uid://btm4uqcfr43cm diff --git a/flumi/Scripts/Utils/Lua/DOM.gd b/flumi/Scripts/Utils/Lua/DOM.gd index 7013211..acb2045 100644 --- a/flumi/Scripts/Utils/Lua/DOM.gd +++ b/flumi/Scripts/Utils/Lua/DOM.gd @@ -95,7 +95,7 @@ static func get_element_last_child_handler(vm: LuauVM, dom_parser: HTMLParser, l # DOM Manipulation Methods -static func handle_element_append(operation: Dictionary, dom_parser: HTMLParser, lua_api) -> void: +static func handle_element_append(operation: Dictionary, dom_parser: HTMLParser) -> void: var parent_id: String = operation.parent_id var child_id: String = operation.child_id @@ -153,7 +153,7 @@ static func handle_element_remove(operation: Dictionary, dom_parser: HTMLParser) if all_elements_index >= 0: dom_parser.parse_result.all_elements.remove_at(all_elements_index) -static func handle_insert_before(operation: Dictionary, dom_parser: HTMLParser, lua_api) -> void: +static func handle_insert_before(operation: Dictionary, dom_parser: HTMLParser) -> void: var parent_id: String = operation.parent_id var new_child_id: String = operation.new_child_id var reference_child_id: String = operation.reference_child_id diff --git a/flumi/Scripts/Utils/Lua/ThreadedVM.gd b/flumi/Scripts/Utils/Lua/ThreadedVM.gd index 81e9197..cd03640 100644 --- a/flumi/Scripts/Utils/Lua/ThreadedVM.gd +++ b/flumi/Scripts/Utils/Lua/ThreadedVM.gd @@ -472,7 +472,9 @@ func _set_interval_handler(vm: LuauVM) -> int: func get_current_href() -> String: var main_node = Engine.get_main_loop().current_scene - return main_node.current_domain + if main_node: + return main_node.current_domain + return "" func _gurt_select_handler(vm: LuauVM) -> int: var selector: String = vm.luaL_checkstring(1) diff --git a/flumi/Scripts/main.gd b/flumi/Scripts/main.gd index 36f1a5b..6982339 100644 --- a/flumi/Scripts/main.gd +++ b/flumi/Scripts/main.gd @@ -29,15 +29,15 @@ const SELECT = preload("res://Scenes/Tags/select.tscn") const TEXTAREA = preload("res://Scenes/Tags/textarea.tscn") const DIV = preload("res://Scenes/Tags/div.tscn") const AUDIO = preload("res://Scenes/Tags/audio.tscn") +const POSTPROCESS = preload("res://Scenes/Tags/postprocess.tscn") const MIN_SIZE = Vector2i(750, 200) var font_dependent_elements: Array = [] +var current_domain = "" func should_group_as_inline(element: HTMLParser.HTMLElement) -> bool: - # Don't group inputs unless they're inside a form if element.tag_name == "input": - # Check if this element has a form ancestor var parent = element.parent while parent: if parent.tag_name == "form": @@ -60,8 +60,6 @@ func _ready(): call_deferred("render") -var current_domain = "" # Store current domain for display - func resolve_url(href: String) -> String: return URLUtils.resolve_url(current_domain, href) @@ -193,6 +191,20 @@ func render_content(html_bytes: PackedByteArray) -> void: remove_child(lua_api) lua_api.queue_free() active_tab.lua_apis.clear() + + var existing_postprocess = [] + for child in get_children(): + if child is HTMLPostprocess: + existing_postprocess.append(child) + + for postprocess in existing_postprocess: + remove_child(postprocess) + postprocess.queue_free() + + if active_tab.background_panel: + var existing_overlay = active_tab.background_panel.get_node_or_null("PostprocessOverlay") + if existing_overlay: + existing_overlay.queue_free() else: var existing_lua_apis = [] for child in get_children(): @@ -204,6 +216,20 @@ func render_content(html_bytes: PackedByteArray) -> void: remove_child(lua_api) lua_api.queue_free() + var postprocess_nodes: Array[Node] = [] + for child in get_children(): + if child is HTMLPostprocess: + postprocess_nodes.append(child) + for node in postprocess_nodes: + remove_child(node) + node.queue_free() + + var default_panel = website_container.get_parent() + if default_panel and default_panel.has_method("get_node_or_null"): + var existing_overlay = default_panel.get_node_or_null("PostprocessOverlay") + if existing_overlay: + existing_overlay.queue_free() + if target_container.get_parent() and target_container.get_parent().name == "BodyMarginContainer": var body_margin_container = target_container.get_parent() var scroll_container = body_margin_container.get_parent() @@ -320,6 +346,12 @@ func render_content(html_bytes: PackedByteArray) -> void: if parse_result.external_scripts and not parse_result.external_scripts.is_empty(): await parser.process_external_scripts(lua_api, null, current_domain) + var postprocess_element = parser.process_postprocess() + if postprocess_element: + var postprocess_node = POSTPROCESS.instantiate() + add_child(postprocess_node) + await postprocess_node.init(postprocess_element, parser) + active_tab.current_url = current_domain active_tab.has_content = true diff --git a/flumi/Shaders/chrome.gdshader b/flumi/Shaders/chrome.gdshader new file mode 100644 index 0000000..d511937 --- /dev/null +++ b/flumi/Shaders/chrome.gdshader @@ -0,0 +1,29 @@ +// Chromatic Aberration Shader by https://godotshaders.com/shader/chromatic-abberation/ +// All credits to the original author!!! + +shader_type canvas_item; + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; + +uniform int levels = 3; +uniform float spread = 0.01; + +vec3 chromatic_slice(float t){ + vec3 res = vec3(1.0-t, 1.0 - abs(t - 1.0), t - 1.0); + return max(res, 0.0); +} + +void fragment(){ + vec3 sum; + COLOR.rgb = vec3(0); + vec2 offset = (UV - vec2(0.5))*vec2(1,-1); + for(int i = 0; i < levels; i++){ + float t = 2.0*float(i)/float(levels-1); // range 0.0->2.0 + vec3 slice = vec3(1.0-t, 1.0 - abs(t - 1.0), t - 1.0); + slice = max(slice, 0.0); + sum += slice; + vec2 slice_offset = (t-1.0)*spread*offset; + COLOR.rgb += slice * texture(SCREEN_TEXTURE, SCREEN_UV + slice_offset).rgb; + } + COLOR.rgb /= sum; +} \ No newline at end of file diff --git a/flumi/Shaders/chrome.gdshader.uid b/flumi/Shaders/chrome.gdshader.uid new file mode 100644 index 0000000..9056082 --- /dev/null +++ b/flumi/Shaders/chrome.gdshader.uid @@ -0,0 +1 @@ +uid://dbkni4dqt0ral diff --git a/flumi/Shaders/crt.gdshader b/flumi/Shaders/crt.gdshader new file mode 100644 index 0000000..b7e74cb --- /dev/null +++ b/flumi/Shaders/crt.gdshader @@ -0,0 +1,90 @@ +/* License CC BY-NC-SA 4.0 Deed */ +/* https://creativecommons.org/licenses/by-nc-sa/4.0/ */ +/* Fork of Ryk's VCR distortion shader */ +/* https://www.shadertoy.com/view/ldjGzV */ + +shader_type canvas_item; + +uniform sampler2D screen_texture: hint_screen_texture, filter_linear_mipmap, repeat_disable; + +group_uniforms Image; +uniform float curvature: hint_range(0., 10., .01) = 2.; +uniform float skip: hint_range(0., 1., .01) = 1.; +uniform float image_flicker: hint_range(0., 1., .01) = 1.; + +group_uniforms Vignette; +uniform float vignette_flicker_speed: hint_range(0., 2., .01) = 1.; +uniform float vignette_strength: hint_range(0., 2., 0.01) = 1.; + +group_uniforms Scanlines; +uniform float small_scanlines_speed: hint_range(0., 10., .01) = 1.; +uniform float small_scanlines_proximity: hint_range(.01, 2., .01) = 1.; +uniform float small_scanlines_opacity: hint_range(0.01, 5., .01) = 1.; +uniform float scanlines_opacity: hint_range(0., 2., .01) = 1.; +uniform float scanlines_speed: hint_range(0., 5., .01) = 1.; +uniform float scanline_thickness: hint_range(0., .6, .01) = 0.5; +uniform float scanlines_spacing: hint_range(0.3, 3., .01) = 1.; + +group_uniforms Noise; +uniform sampler2D noise_texture: filter_linear_mipmap, repeat_enable; + +float noise(vec2 p, vec2 uv) +{ + float s = texture(noise_texture,vec2(1.*TIME,2.*TIME)*8. + p*1.).x; + s *= s; + return s; +} + +float onOff(float a, float b, float c) +{ + return step(c, sin(TIME + a*cos(TIME*b))); +} + +float ramp(float y, float start, float end) +{ + float inside = step(start,y) - step(end,y); + float fact = (y-start)/(end-start)*inside; + return (1.-fact) * inside; +} + +float stripes(vec2 uv) +{ + float noi = noise(uv*vec2(0.5,1.) + vec2(1.,3.), uv)*scanlines_opacity; + return ramp(mod(uv.y*4.*scanlines_spacing + TIME*scanlines_speed/(2.*scanlines_spacing)+sin(TIME*scanlines_speed + sin(TIME*scanlines_speed*0.63*scanlines_spacing)),1.),scanline_thickness,.6)*noi; +} + +vec3 getVideo(vec2 uv) +{ + vec2 look = uv; + float window = 1./(1.+20.*(look.y-mod(TIME/4.,1.))*(look.y-mod(TIME/4.,1.)))*image_flicker; + look.x = look.x + sin(look.y*10. + TIME)/50.*onOff(4.,4.,.3)*(1.+cos(TIME*80.))*window; + float vShift = 0.4*onOff(2.,3.,.9)*(sin(TIME)*sin(TIME*20.)+(0.5 + 0.1*sin(TIME*200.)*cos(TIME)))*skip; + look.y = mod(look.y + vShift, 1.); + vec3 video = texture(screen_texture,look).xyz; + return video; +} + +vec2 screenDistort(vec2 uv) +{ + uv -= vec2(.5,.5); + uv = uv*1.2*(1./1.2+curvature*uv.x*uv.x*uv.y*uv.y); + uv += vec2(.5,.5); + return uv; +} + +void fragment() +{ + vec2 uv = FRAGCOORD.xy / (1.0 / SCREEN_PIXEL_SIZE).xy; + uv = screenDistort(uv); + vec3 video = getVideo(uv); + float vigAmt = 3.+.3*sin(TIME*vignette_flicker_speed+1. + 5.*cos(TIME*5.*vignette_flicker_speed+1.)); + vigAmt *= vignette_strength; + float vignette = (1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5)); + + video += stripes(uv); + video += noise(uv*2., uv)/2.; + video *= vignette; + video *= (12./small_scanlines_opacity+mod(uv.y*30.*small_scanlines_proximity+TIME*small_scanlines_speed,1.))/13.*small_scanlines_opacity; + + COLOR = vec4(video,1.0); +} \ No newline at end of file diff --git a/flumi/Shaders/crt.gdshader.uid b/flumi/Shaders/crt.gdshader.uid new file mode 100644 index 0000000..2ed9106 --- /dev/null +++ b/flumi/Shaders/crt.gdshader.uid @@ -0,0 +1 @@ +uid://db3f2xubcujnq diff --git a/flumi/Shaders/dither.gdshader b/flumi/Shaders/dither.gdshader new file mode 100644 index 0000000..0e0755c --- /dev/null +++ b/flumi/Shaders/dither.gdshader @@ -0,0 +1,45 @@ +//GODOT 4 + +shader_type canvas_item; + +uniform float pixel = 1.0; +uniform sampler2D pallete; + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; + +const float bit = 6.0; +const mat4 bayer = mat4( + vec4(1.0, 9.0, 3.0, 11.0), + vec4(13.0, 5.0, 15.0, 7.0), + vec4(4.0, 12.0, 2.0, 10.0), + vec4(16.0, 8.0, 14.0, 6.0)); + + +float getbayer(int x, int y) +{ + return bayer[x][y]; +} + +void fragment() { + vec4 original = texture(TEXTURE, UV); + + vec2 FUV = floor(FRAGCOORD.xy / pixel) / floor((1.0 / SCREEN_PIXEL_SIZE) / pixel); + + vec4 _color = texture(SCREEN_TEXTURE, SCREEN_UV); + vec4 color = _color * texture(pallete, vec2(_color.r, 1.0)); + + + float b = getbayer(int(FRAGCOORD.x) % 4, int(FRAGCOORD.y) % 4);// * 1.0) / 1.0; + vec2 uv = FRAGCOORD.xy / SCREEN_PIXEL_SIZE; + vec4 col_noise = color; + vec3 noise = vec3(fract(sin(dot(FUV, vec2(12.9898, 78.233))) * 43758.5453)); + noise *= 0.1; + noise.xy *= (b / 16.0) * 1.5; + col_noise.rgb += noise; //noise effect + + vec4 post = col_noise * floor(col_noise * 4.0) / 4.0; //noise + post-effect + + COLOR *= post; + + +} \ No newline at end of file diff --git a/flumi/Shaders/dither.gdshader.uid b/flumi/Shaders/dither.gdshader.uid new file mode 100644 index 0000000..165d045 --- /dev/null +++ b/flumi/Shaders/dither.gdshader.uid @@ -0,0 +1 @@ +uid://bggtn4uh67v0u diff --git a/flumi/Shaders/film.gdshader b/flumi/Shaders/film.gdshader new file mode 100644 index 0000000..620e1a1 --- /dev/null +++ b/flumi/Shaders/film.gdshader @@ -0,0 +1,20 @@ +shader_type canvas_item; + +// Uniforms +uniform sampler2D screen_texture : hint_screen_texture; +uniform float grain_amount : hint_range(0.0, 1.0) = 0.05; // Adjust the amount of grain +uniform float grain_size : hint_range(0.1, 10.0) = 1.0; // Adjust the size of the grain + +void fragment() { + // Sample the original screen texture + vec4 original_color = texture(screen_texture, SCREEN_UV); + + // Generate random noise + float noise = (fract(sin(dot(UV, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) * 2.0; + + // Add noise to the original color + original_color.rgb += noise * grain_amount * grain_size; + + // Clamp the final color to make sure it stays in the valid range + COLOR = clamp(original_color, 0.0, 1.0); +} \ No newline at end of file diff --git a/flumi/Shaders/film.gdshader.uid b/flumi/Shaders/film.gdshader.uid new file mode 100644 index 0000000..7a8bca1 --- /dev/null +++ b/flumi/Shaders/film.gdshader.uid @@ -0,0 +1 @@ +uid://bss3x1xthtaef diff --git a/flumi/Shaders/foliage.gdshader b/flumi/Shaders/foliage.gdshader new file mode 100644 index 0000000..a97c533 --- /dev/null +++ b/flumi/Shaders/foliage.gdshader @@ -0,0 +1,32 @@ +shader_type canvas_item; + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; + +uniform float x_intensity = 3.0; +uniform float y_intensity = 0.5; +uniform float offset = 0.0; +uniform float speed : hint_range(0, 20) = 2.0; +uniform float wave_frequency : hint_range(0, 100) = 20; +uniform float wave_length : hint_range(50, 800) = 200.0; + +void fragment() { + vec2 real_uv = UV; + + vec2 vecToBottom = vec2(1, 1) - UV.y; + float distToBottom = length(vecToBottom); + + float final_speed = TIME * (speed / 4.0) + offset; + + float time_var = (cos(final_speed) * cos(final_speed * 4.0) * cos(final_speed * 2.0))/(200.0); + float time_var2 = (cos(final_speed) * cos(final_speed * 6.0) * cos(final_speed * 2.0))/(200.0); + + float wave_from_x = (cos(real_uv.x * 100.0)/1000.0); + float wave_large_from_x = cos(TIME + (real_uv.x * wave_frequency))/wave_length; + + float offset_x = time_var * (distToBottom * x_intensity) + wave_from_x + (wave_large_from_x); + float offset_y = time_var2 * (distToBottom * y_intensity); + + vec2 distortion_offset = vec2(offset_x, offset_y); + + COLOR = texture(SCREEN_TEXTURE, SCREEN_UV + distortion_offset); +} \ No newline at end of file diff --git a/flumi/Shaders/foliage.gdshader.uid b/flumi/Shaders/foliage.gdshader.uid new file mode 100644 index 0000000..b2b322c --- /dev/null +++ b/flumi/Shaders/foliage.gdshader.uid @@ -0,0 +1 @@ +uid://12ar0h66dukp diff --git a/flumi/Shaders/future.gdshader.uid b/flumi/Shaders/future.gdshader.uid new file mode 100644 index 0000000..698408e --- /dev/null +++ b/flumi/Shaders/future.gdshader.uid @@ -0,0 +1 @@ +uid://c8nv7tds2neww diff --git a/flumi/Shaders/lensflare.gdshader b/flumi/Shaders/lensflare.gdshader new file mode 100644 index 0000000..7c1407a --- /dev/null +++ b/flumi/Shaders/lensflare.gdshader @@ -0,0 +1,95 @@ +// TRANSLATED & MODIFIED FROM: https://www.shadertoy.com/view/4sX3Rs + +shader_type canvas_item; +render_mode blend_mix; + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; + +uniform vec2 sun_position = vec2(400.0, 0.0); +uniform vec3 tint = vec3(1.4,1.2,1.0); +uniform sampler2D noise_texture; + +float noise_float(float t, vec2 texResolution) +{ + return texture(noise_texture,vec2(t,0.0)/texResolution).x; +} +float noise_vec2(vec2 t, vec2 texResolution) +{ + return texture(noise_texture,t/texResolution).x; +} + +vec3 lensflare(vec2 uv,vec2 pos, vec2 texResolution) +{ + vec2 main = uv-pos; + vec2 uvd = uv*(length(uv)); + + float ang = atan(main.x,main.y); + float dist = length(main); + dist = pow(dist,0.1); + + float n = noise_vec2(vec2(ang*16.0,dist*32.0), texResolution); + + // Do not need an artificial sun + //float f0 = 1.0/(length(uv-pos)*16.0+1.0); + //f0 = f0 + f0*(sin(noise_float(sin(ang*2.+pos.x)*4.0 - cos(ang*3.+pos.y), texResolution)*16.)*.1 + dist*.1 + .8); + + float f1 = max(0.01-pow(length(uv+1.2*pos),1.9),.0)*7.0; + + float f2 = max(1.0/(1.0+32.0*pow(length(uvd+0.8*pos),2.0)),.0)*00.25; + float f22 = max(1.0/(1.0+32.0*pow(length(uvd+0.85*pos),2.0)),.0)*00.23; + float f23 = max(1.0/(1.0+32.0*pow(length(uvd+0.9*pos),2.0)),.0)*00.21; + + vec2 uvx = mix(uv,uvd,-0.5); + + float f4 = max(0.01-pow(length(uvx+0.4*pos),2.4),.0)*6.0; + float f42 = max(0.01-pow(length(uvx+0.45*pos),2.4),.0)*5.0; + float f43 = max(0.01-pow(length(uvx+0.5*pos),2.4),.0)*3.0; + + uvx = mix(uv,uvd,-.4); + + float f5 = max(0.01-pow(length(uvx+0.2*pos),5.5),.0)*2.0; + float f52 = max(0.01-pow(length(uvx+0.4*pos),5.5),.0)*2.0; + float f53 = max(0.01-pow(length(uvx+0.6*pos),5.5),.0)*2.0; + + uvx = mix(uv,uvd,-0.5); + + float f6 = max(0.01-pow(length(uvx-0.3*pos),1.6),.0)*6.0; + float f62 = max(0.01-pow(length(uvx-0.325*pos),1.6),.0)*3.0; + float f63 = max(0.01-pow(length(uvx-0.35*pos),1.6),.0)*5.0; + + vec3 c = vec3(.0); + + c.r+=f2+f4+f5+f6; c.g+=f22+f42+f52+f62; c.b+=f23+f43+f53+f63; + c = c*1.3 - vec3(length(uvd)*.05); + + // Do not need an artificial sun + //c+=vec3(f0); + + return c; +} + +vec3 cc(vec3 color, float factor,float factor2) // color modifier +{ + float w = color.x+color.y+color.z; + return mix(color,vec3(w)*factor,w*factor2); +} + +void fragment() +{ + vec2 texResolution = 1.0 / TEXTURE_PIXEL_SIZE; + vec2 resolution = 1.0 / SCREEN_PIXEL_SIZE; + + vec2 uv = FRAGCOORD.xy / resolution.xy - 0.5; + uv.x *= resolution.x/resolution.y; //fix aspect ratio + vec2 mouse = (sun_position.xy / resolution.xy) - vec2(0.5, 0.5); + mouse.x *= resolution.x / resolution.y; //fix aspect ratio + + vec4 previousColor = texture(SCREEN_TEXTURE, SCREEN_UV); + + vec3 color = previousColor.rgb; + + color += tint * lensflare(uv, mouse.xy, texResolution); + color -= noise_vec2(FRAGCOORD.xy, texResolution)*.015; + color = cc(color,.5,.1); + COLOR = vec4(color,1.0); +} \ No newline at end of file diff --git a/flumi/Shaders/lensflare.gdshader.uid b/flumi/Shaders/lensflare.gdshader.uid new file mode 100644 index 0000000..ada4b2a --- /dev/null +++ b/flumi/Shaders/lensflare.gdshader.uid @@ -0,0 +1 @@ +uid://c6auxoe0vpq46 diff --git a/flumi/Shaders/pencil.gdshader b/flumi/Shaders/pencil.gdshader new file mode 100644 index 0000000..2eafa18 --- /dev/null +++ b/flumi/Shaders/pencil.gdshader @@ -0,0 +1,58 @@ +shader_type canvas_item; + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; +uniform vec4 u_bgColor: source_color = vec4(1.0, 1.0, 1.0, 1.0); +uniform float u_bgColorFactor: hint_range(0.0, 1.0) = 0.4; +uniform vec4 u_patternColor: source_color = vec4(0.0, 0.0, 0.0, 1.0); + +uniform float u_threshold1: hint_range(0.0, 1.0) = 0.75; +uniform float u_threshold2: hint_range(0.0, 1.0) = 0.50; +uniform float u_threshold3: hint_range(0.0, 1.0) = 0.25; +uniform float u_threshold4: hint_range(0.0, 1.0) = 0.05; + +uniform vec2 u_bgTiling = vec2(1.0, 1.0); +uniform vec2 u_patternTiling = vec2(1.0, 1.0); + +uniform sampler2D u_bgTexture; +uniform sampler2D u_patternTexture; + +const float C2_SQRT2 = 0.707106781; +const mat2 ROT_45 = mat2(vec2(C2_SQRT2, -C2_SQRT2), vec2(C2_SQRT2, C2_SQRT2)); +const vec4 COLOR_WHITE = vec4(1.0, 1.0, 1.0, 1.0); + +float getIntensity(vec3 color) +{ + return 0.299*color.r + 0.587*color.g + 0.114*color.b; +} + +vec4 getPatternColor(vec2 uv, float intensity) +{ + vec2 patternUV1 = vec2(-uv.x, uv.y) * u_patternTiling; + vec2 patternUV2 = uv * u_patternTiling; + vec2 patternUV3 = ROT_45*(uv + vec2(0.2358, 0.9123)) * u_patternTiling; + vec2 patternUV4 = (vec2(uv.x, -uv.y) + vec2(0.4123, 0.7218)) * u_patternTiling; + vec4 pCol1 = texture(u_patternTexture, patternUV1); + vec4 pCol2 = texture(u_patternTexture, patternUV2); + vec4 pCol3 = texture(u_patternTexture, patternUV3); + vec4 pCol4 = texture(u_patternTexture, patternUV4); + + if(intensity > u_threshold1) + return vec4(1.0, 1.0, 1.0, 1.0); + if(intensity > u_threshold2) + return mix(pCol1, COLOR_WHITE, 0.5); + if(intensity > u_threshold3) + return mix(pCol1*pCol2, COLOR_WHITE, 0.3); + if(intensity > u_threshold4) + return mix(pCol1*pCol2*pCol3, COLOR_WHITE, 0.1); + return pCol1*pCol2*pCol3*pCol4*0.8; +} + +void fragment() +{ + vec4 origColor = texture(SCREEN_TEXTURE, SCREEN_UV); + float intensity = getIntensity(origColor.rgb); + vec4 bgColor = mix(texture(u_bgTexture, UV*u_bgTiling), u_bgColor, u_bgColorFactor); + vec4 patternColor = getPatternColor(UV, intensity); + vec4 color = mix(u_patternColor, bgColor, getIntensity(patternColor.rgb)); + COLOR = color; +} \ No newline at end of file diff --git a/flumi/Shaders/pencil.gdshader.uid b/flumi/Shaders/pencil.gdshader.uid new file mode 100644 index 0000000..a998c93 --- /dev/null +++ b/flumi/Shaders/pencil.gdshader.uid @@ -0,0 +1 @@ +uid://c54knriu0lot8 diff --git a/flumi/Shaders/pixelate.gdshader.uid b/flumi/Shaders/pixelate.gdshader.uid new file mode 100644 index 0000000..437bc23 --- /dev/null +++ b/flumi/Shaders/pixelate.gdshader.uid @@ -0,0 +1 @@ +uid://b4qebk1wtx6pj diff --git a/flumi/Shaders/rblur.gdshader b/flumi/Shaders/rblur.gdshader new file mode 100644 index 0000000..fd0a18e --- /dev/null +++ b/flumi/Shaders/rblur.gdshader @@ -0,0 +1,27 @@ +/* + 放射状ブラーエフェクト by あるる(きのもと 結衣) @arlez80 + Radial Blur Effect by Yui Kinomoto + + MIT License +*/ + +shader_type canvas_item; +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; + +// 発射中央部 +uniform vec2 blur_center = vec2( 0.5, 0.5 ); +// ブラー強度 +uniform float blur_power : hint_range( 0.0, 1.0 ) = 0.01; +// サンプリング回数 +uniform int sampling_count : hint_range( 1, 64 ) = 2; + +void fragment( ) +{ + vec2 direction = SCREEN_UV - blur_center; + vec3 c = vec3( 0.0, 0.0, 0.0 ); + float f = 1.0 / float( sampling_count ); + for( int i=0; i < sampling_count; i++ ) { + c += texture( SCREEN_TEXTURE, SCREEN_UV - blur_power * direction * float(i) ).rgb * f; + } + COLOR.rgb = c; +} diff --git a/flumi/Shaders/rblur.gdshader.uid b/flumi/Shaders/rblur.gdshader.uid new file mode 100644 index 0000000..d0b3093 --- /dev/null +++ b/flumi/Shaders/rblur.gdshader.uid @@ -0,0 +1 @@ +uid://bcwhtc0sjmwr3 diff --git a/flumi/Shaders/retro.gdshader.uid b/flumi/Shaders/retro.gdshader.uid new file mode 100644 index 0000000..dfc8a75 --- /dev/null +++ b/flumi/Shaders/retro.gdshader.uid @@ -0,0 +1 @@ +uid://c366ik3prmltu diff --git a/flumi/Shaders/snowfall.gdshader b/flumi/Shaders/snowfall.gdshader new file mode 100644 index 0000000..6382797 --- /dev/null +++ b/flumi/Shaders/snowfall.gdshader @@ -0,0 +1,59 @@ +// Modified version of https://godotshaders.com/shader/multilayer-snowfall-shader/ +// All credits to the original author!!! + +shader_type canvas_item; + +uniform float spread : hint_range(0.0, 1.5) = 0.5; +uniform float size : hint_range(0.01, 5.0) = 0.5; +uniform vec4 snow_color : source_color = vec4(1.0); +uniform float snow_transparency: hint_range(-0.5, 1.0) = 0.2; + +uniform float speed : hint_range(0.0, 10.0) = 0.5; +uniform float wind : hint_range(-2.0, 2.0) = 0.0; +uniform int num_of_layers = 40; + +const mat3 NOISE_MATRIX = mat3( + vec3(13.323122, 23.5112, 21.71123), + vec3(21.1212, 28.7312, 11.9312), + vec3(21.8112, 14.7212, 61.3934) +); + +vec3 generate_snowflake(vec2 coord, float layer_index, float time, float wind_strength) { + float layer_scale = 1.0 + layer_index * 0.5 / (max(size, 0.01) * 2.0); + vec2 scaled_coord = coord * layer_scale; + + vec2 movement = vec2( + scaled_coord.y * (spread * mod(layer_index * 7.238917, 1.0) - spread * 0.5) + + (-wind_strength) * speed * time * 0.5, + -speed * time / (1.0 + layer_index * 0.5 * 0.03) + ); + vec2 final_coord = scaled_coord + movement; + + vec3 noise_input = vec3(floor(final_coord), 31.189 + layer_index); + vec3 noise_val = floor(noise_input) * 0.00001 + fract(noise_input); + vec3 random = fract((31415.9 + noise_val) / fract(NOISE_MATRIX * noise_val)); + + vec2 shape = abs(mod(final_coord, 1.0) - 0.5 + 0.9 * random.xy - 0.45); + shape += 0.01 * abs(2.0 * fract(10.0 * final_coord.yx) - 1.0); + + float depth_offset = 5.0 * sin(time * 0.1); + float edge_softness = 0.005 + 0.05 * min(0.5 * abs(layer_index - 5.0 - depth_offset), 1.0); + + float shape_value = 0.6 * max(shape.x - shape.y, shape.x + shape.y) + max(shape.x, shape.y) - 0.01; + + return vec3(smoothstep(edge_softness, -edge_softness, shape_value) * + (random.x / (1.0 + 0.02 * layer_index * 0.5))); +} + +void fragment() { + vec3 snow_accumulation = vec3(0.0); + + for (int i = 0; i < num_of_layers; i++) { + snow_accumulation += generate_snowflake(UV, float(i), TIME, wind); + } + + float snow_intensity = clamp(length(snow_accumulation), 0.0, 1.0); + vec4 transparency_color = vec4(snow_color.rgb * (1.0 + snow_transparency), snow_intensity); + + COLOR = transparency_color; +} \ No newline at end of file diff --git a/flumi/Shaders/snowfall.gdshader.uid b/flumi/Shaders/snowfall.gdshader.uid new file mode 100644 index 0000000..e1f1833 --- /dev/null +++ b/flumi/Shaders/snowfall.gdshader.uid @@ -0,0 +1 @@ +uid://deof0r34dt78d diff --git a/flumi/Shaders/vignette.gdshader b/flumi/Shaders/vignette.gdshader new file mode 100644 index 0000000..9edb280 --- /dev/null +++ b/flumi/Shaders/vignette.gdshader @@ -0,0 +1,17 @@ +shader_type canvas_item; + +uniform float inner_radius = 0.1; +uniform float outer_radius = 1; +uniform float vignette_strength = 1.0; +uniform float dither_strength = 0.03; +uniform vec4 vignette_color: source_color; + + +void fragment() { + float dist = distance(UV, vec2(0.5)); + + float vignette = smoothstep(inner_radius, outer_radius, dist) * vignette_strength; + float dither = fract(sin(dot(UV, vec2(12.9898, 78.233))) * 43758.5453123) * dither_strength; + + COLOR = vec4(vignette_color.rgb, vignette + dither); +} \ No newline at end of file diff --git a/flumi/Shaders/vignette.gdshader.uid b/flumi/Shaders/vignette.gdshader.uid new file mode 100644 index 0000000..6eda06c --- /dev/null +++ b/flumi/Shaders/vignette.gdshader.uid @@ -0,0 +1 @@ +uid://boba7hm3vito8 diff --git a/flumi/Shaders/wobbly.gdshader.uid b/flumi/Shaders/wobbly.gdshader.uid new file mode 100644 index 0000000..a4f912c --- /dev/null +++ b/flumi/Shaders/wobbly.gdshader.uid @@ -0,0 +1 @@ +uid://186q3n8sc7qw diff --git a/tests/clipboard.html b/tests/clipboard.html index fa828da..ff46aad 100644 --- a/tests/clipboard.html +++ b/tests/clipboard.html @@ -14,6 +14,8 @@ .copy-url-btn { bg-[#8b5cf6] text-white hover:bg-[#7c3aed] } + +