Release/v6.2 #35

Merged
ChaoticByte merged 9 commits from release/v6.2 into main 2025-01-10 19:58:28 +00:00
24 changed files with 198 additions and 36 deletions

View file

@ -68,7 +68,7 @@ shader_type canvas_item;
#include "res://shaderlib/hsv.gdshaderinc" #include "res://shaderlib/hsv.gdshaderinc"
//!load ./swamp.jpg //!load ./examples/images/swamp.jpg
void fragment() { void fragment() {
COLOR = hsv_offset(COLOR, 0.32, 0.2, 0.0); COLOR = hsv_offset(COLOR, 0.32, 0.2, 0.0);

View file

@ -1,6 +1,6 @@
shader_type canvas_item; shader_type canvas_item;
//!load ./swamp.jpg //!load ./images/swamp.jpg
const vec2 offset_r = vec2(-0.002, -0.002); const vec2 offset_r = vec2(-0.002, -0.002);
const vec2 offset_g = vec2(0., 0.); const vec2 offset_g = vec2(0., 0.);

View file

@ -0,0 +1,13 @@
shader_type canvas_item;
#include "res://shaderlib/hsv.gdshaderinc"
#include "res://shaderlib/effects.gdshaderinc"
//!load ./images/swamp.jpg
void fragment() {
COLOR = pixelate(TEXTURE, UV, 200.0);
vec4 hsv = rgb2hsv(COLOR);
COLOR = hsv_offset(COLOR, 0.65, .42-(hsv.y*.3), -.125);
COLOR = hsv_multiply(COLOR, 1.0, 1.0, 1.25);
}

View file

@ -0,0 +1,9 @@
shader_type canvas_item;
//!load ./images/noisy.png
#include "res://shaderlib/denoise.gdshaderinc"
void fragment() {
COLOR = smart_denoise(TEXTURE, UV, 12.0, 1.0, .12);
}

View file

@ -1,6 +1,6 @@
shader_type canvas_item; shader_type canvas_item;
//!load ./swamp.jpg //!load ./images/swamp.jpg
void fragment() { void fragment() {
float b = (COLOR.r + COLOR.g + COLOR.b) / 3.0; float b = (COLOR.r + COLOR.g + COLOR.b) / 3.0;

View file

@ -1,9 +0,0 @@
shader_type canvas_item;
#include "res://shaderlib/hsv.gdshaderinc"
//!load ./swamp.jpg
void fragment() {
COLOR = hsv_multiply(hsv_offset(COLOR, -0.3, 0.9, 0.0), 1.0, 0.44, 1.0);
}

View file

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Before After
Before After

View file

@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://c1mh1d2f3u4ju" uid="uid://c1mh1d2f3u4ju"
path="res://.godot/imported/grass.png-30af7213ed2d70b810b4ae788314a9e9.ctex" path="res://.godot/imported/grass.png-61a458998da568ce60ccb8a0c7caaf6d.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://examples/grass.png" source_file="res://examples/images/grass.png"
dest_files=["res://.godot/imported/grass.png-30af7213ed2d70b810b4ae788314a9e9.ctex"] dest_files=["res://.godot/imported/grass.png-61a458998da568ce60ccb8a0c7caaf6d.ctex"]
[params] [params]

BIN
examples/images/noisy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cfe2d0qes5x87"
path="res://.godot/imported/noisy.png-1b2e79340785c6c0f50d5bad5ce97356.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://examples/images/noisy.png"
dest_files=["res://.godot/imported/noisy.png-1b2e79340785c6c0f50d5bad5ce97356.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

View file

Before

Width:  |  Height:  |  Size: 477 KiB

After

Width:  |  Height:  |  Size: 477 KiB

Before After
Before After

View file

@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://ckjb0agn5btv7" uid="uid://ckjb0agn5btv7"
path="res://.godot/imported/swamp.jpg-8e3eac7e7aacce65638e712310cdb35c.ctex" path="res://.godot/imported/swamp.jpg-1dfdcd52a5ef03d42a82a7f06acefa98.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://examples/swamp.jpg" source_file="res://examples/images/swamp.jpg"
dest_files=["res://.godot/imported/swamp.jpg-8e3eac7e7aacce65638e712310cdb35c.ctex"] dest_files=["res://.godot/imported/swamp.jpg-1dfdcd52a5ef03d42a82a7f06acefa98.ctex"]
[params] [params]

View file

@ -1,15 +1,13 @@
shader_type canvas_item; shader_type canvas_item;
//!load ./swamp.jpg //!load ./images/swamp.jpg
// Settings // Settings
const float threshold = 0.5; const float threshold = 0.6;
// //
void fragment() { void fragment() {
vec4 tex = texture(TEXTURE , UV); vec4 tex = texture(TEXTURE , UV);
COLOR.r = min(tex.r, threshold); COLOR.rgb = min(tex.rgb, vec3(threshold));
COLOR.g = min(tex.g, threshold);
COLOR.b = min(tex.b, threshold);
COLOR.a = tex.a; COLOR.a = tex.a;
} }

View file

@ -1,7 +1,7 @@
shader_type canvas_item; shader_type canvas_item;
//!steps 9 //!steps 9
//!load ./swamp.jpg //!load ./images/swamp.jpg
const float strength = 0.01; const float strength = 0.01;

View file

@ -3,8 +3,8 @@ shader_type canvas_item;
#include "res://shaderlib/transform.gdshaderinc" #include "res://shaderlib/transform.gdshaderinc"
#include "res://shaderlib/transparency.gdshaderinc" #include "res://shaderlib/transparency.gdshaderinc"
//!load ./swamp.jpg //!load ./images/swamp.jpg
//!load+ img2 ./grass.png //!load+ img2 ./images/grass.png
uniform sampler2D img2: repeat_disable, filter_nearest; uniform sampler2D img2: repeat_disable, filter_nearest;

View file

@ -11,7 +11,7 @@ config_version=5
[application] [application]
config/name="Fragmented" config/name="Fragmented"
config/version="v6.1" config/version="v6.2"
run/main_scene="res://scenes/main.tscn" run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.3", "Mobile") config/features=PackedStringArray("4.3", "Mobile")
run/low_processor_mode=true run/low_processor_mode=true

View file

@ -134,6 +134,7 @@ offset_bottom = 32.0
text = "Save As" text = "Save As"
[node name="SaveImageButton" type="Button" parent="Editor"] [node name="SaveImageButton" type="Button" parent="Editor"]
unique_name_in_owner = true
layout_mode = 1 layout_mode = 1
anchors_preset = 1 anchors_preset = 1
anchor_left = 1.0 anchor_left = 1.0
@ -141,6 +142,7 @@ anchor_right = 1.0
offset_left = -72.0 offset_left = -72.0
offset_bottom = 32.0 offset_bottom = 32.0
grow_horizontal = 0 grow_horizontal = 0
disabled = true
text = "Export" text = "Export"
[node name="FitImageButton" type="Button" parent="Editor"] [node name="FitImageButton" type="Button" parent="Editor"]

View file

@ -0,0 +1,66 @@
/* glslSmartDenoise by Michele Morrone, adapted
original code: https://github.com/BrutPitt/glslSmartDeNoise
license of the original code:
BSD 2-Clause License
Copyright (c) 2019-2020 Michele Morrone
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define INV_SQRT_OF_2PI 0.39894228040143267793994605993439 // 1.0/SQRT_OF_2PI
#define INV_PI 0.31830988618379067153776752674503
vec4 smart_denoise(sampler2D tex, vec2 uv, float sigma, float kSigma, float threshold) {
float radius = round(kSigma*sigma);
float radQ = radius * radius;
float invSigmaQx2 = .5 / (sigma * sigma); // 1.0 / (sigma^2 * 2.0)
float invSigmaQx2PI = INV_PI * invSigmaQx2; // 1/(2 * PI * sigma^2)
float invThresholdSqx2 = .5 / (threshold * threshold); // 1.0 / (sigma^2 * 2.0)
float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold; // 1.0 / (sqrt(2*PI) * sigma^2)
vec4 centrPx = texture(tex,uv);
float zBuff = 0.0;
vec4 aBuff = vec4(0.0);
vec2 size = vec2(textureSize(tex, 0));
for (float dx = -radius; dx <= radius; dx++) {
float pt = sqrt(radQ - dx * dx); // pt = yRadius: have circular trend
for (float dy = -pt; dy <= pt; dy++) {
vec2 d = vec2(dx, dy);
float blurFactor = exp( -dot(d, d) * invSigmaQx2 ) * invSigmaQx2PI;
vec4 walkPx = texture(tex,uv+d/size);
vec4 dC = walkPx-centrPx;
float deltaFactor = exp(-dot(dC, dC) * invThresholdSqx2) * invThresholdSqrt2PI * blurFactor;
zBuff += deltaFactor;
aBuff += deltaFactor*walkPx;
}
}
return aBuff/zBuff;
}

View file

@ -0,0 +1,14 @@
// pixelate by lowering uv resolution
vec4 pixelate(sampler2D tex, vec2 uv, float resolution_x) {
vec2 texture_size = vec2(textureSize(tex, 0));
vec2 ratio;
if (texture_size.x > texture_size.y) {
ratio = vec2(texture_size.x / texture_size.y, 1.0);
}
else {
ratio = vec2(1.0, texture_size.y / texture_size.x);
}
vec2 r = ratio * resolution_x;
return texture(tex, trunc(uv * r) / r);
}

View file

@ -73,17 +73,17 @@ func update() -> Array: # returns error messages (strings)
mat.set_shader_parameter( mat.set_shader_parameter(
key, # uniform param name key, # uniform param name
Filesystem.additional_images[key]) Filesystem.additional_images[key])
# assign material
image_sprite.material = mat
# iterate n times # iterate n times
for i in range(steps): for i in range(steps):
# set STEP param # set STEP param
mat.set_shader_parameter("STEP", i) mat.set_shader_parameter("STEP", i)
# assign material
image_sprite.material = mat
# Get viewport texture # Get viewport texture
await RenderingServer.frame_post_draw # for good measure await RenderingServer.frame_post_draw # wait for next frame to get drawn
Filesystem.result = get_texture().get_image() Filesystem.result = get_texture().get_image()
image_sprite.material = null
image_sprite.texture = ImageTexture.create_from_image(Filesystem.result) image_sprite.texture = ImageTexture.create_from_image(Filesystem.result)
image_sprite.material = null
if fit_image: if fit_image:
camera.fit_image() camera.fit_image()
camera.update_vd_zoomlevel() camera.update_vd_zoomlevel()

View file

@ -6,6 +6,8 @@ extends Control
@onready var save_shader_dialog = %SaveShaderDialog @onready var save_shader_dialog = %SaveShaderDialog
@onready var ui_control_filesave = %SaveImageDialog @onready var ui_control_filesave = %SaveImageDialog
@onready var save_image_button = %SaveImageButton
@onready var status_indicator = %StatusIndicator @onready var status_indicator = %StatusIndicator
@onready var error_msg_dialog = %ErrorMessageDialog @onready var error_msg_dialog = %ErrorMessageDialog
@ -121,16 +123,24 @@ const gdshader_builtins = [
"POINT_COORD", "POINT_COORD",
"SPECULAR_SHININESS" "SPECULAR_SHININESS"
] ]
const gdshader_preprocessor = [
"define", "undef", "include", "pragma",
"if", "elif", "ifdef", "ifndef", "else", "endif"
]
# shaderlib # shaderlib
var shaderlib_regex = { var shaderlib_regex = {
"hsv": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/hsv\.gdshaderinc\"'), "hsv": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/hsv\.gdshaderinc\"'),
"transform": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/transform\.gdshaderinc\"'), "transform": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/transform\.gdshaderinc\"'),
"transparency": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/transparency\.gdshaderinc\"') "transparency": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/transparency\.gdshaderinc\"'),
"effects": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/effects\.gdshaderinc\"'),
"denoise": RegEx.create_from_string(r'\s*\#include\s+\"res\:\/\/shaderlib\/denoise\.gdshaderinc\"')
} }
const shaderlib_functions = { const shaderlib_functions = {
"hsv": ["rgb2hsv", "hsv2rgb", "hsv_offset", "hsv_multiply"], "hsv": ["rgb2hsv", "hsv2rgb", "hsv_offset", "hsv_multiply"],
"transform": ["place_texture"], "transform": ["place_texture"],
"transparency": ["alpha_blend"], "transparency": ["alpha_blend"],
"effects": ["pixelate"],
"denoise": ["smart_denoise"]
} }
# #
# configure Highlighter # configure Highlighter
@ -182,6 +192,9 @@ func _on_code_edit_code_completion_requested():
for k in gdshader_builtin_functions + gdshader_sub_functions: for k in gdshader_builtin_functions + gdshader_sub_functions:
code_editor.code_completion_prefixes.append(k) code_editor.code_completion_prefixes.append(k)
code_editor.add_code_completion_option(CodeEdit.KIND_FUNCTION, k, k+"(", Color.INDIAN_RED) code_editor.add_code_completion_option(CodeEdit.KIND_FUNCTION, k, k+"(", Color.INDIAN_RED)
for k in gdshader_preprocessor:
code_editor.code_completion_prefixes.append(k)
code_editor.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, "#" + k, k)
# shaderlib # # shaderlib #
var shader_code = code_editor.text var shader_code = code_editor.text
for key in shaderlib_regex: for key in shaderlib_regex:
@ -257,12 +270,14 @@ func _on_fit_image_button_pressed():
camera.fit_image() camera.fit_image()
func _on_apply_shader_button_pressed(): func _on_apply_shader_button_pressed():
save_image_button.disabled = true
Filesystem.shader_code = code_editor.text Filesystem.shader_code = code_editor.text
var errors = await compositor.update() var errors = await compositor.update()
if len(errors) > 0: if len(errors) > 0:
update_status(Status.ERROR, "\n".join(errors)) update_status(Status.ERROR, "\n".join(errors))
else: else:
update_status(Status.OKAY) update_status(Status.OKAY)
save_image_button.disabled = false
func _on_save_image_button_pressed(): func _on_save_image_button_pressed():
if Filesystem.result != null: if Filesystem.result != null:

View file

@ -61,15 +61,30 @@ func save_result(path: String):
func load_shader(path: String): func load_shader(path: String):
print("Load ", path) print("Load ", path)
var file = FileAccess.open(path, FileAccess.READ) var file = FileAccess.open(path, FileAccess.READ)
if file != null:
self.shader_code = file.get_as_text() self.shader_code = file.get_as_text()
if "/" in path: # update current working directory if "/" in path: # update current working directory
self.cwd = path.substr(0, path.rfind("/")) self.cwd = path.substr(0, path.rfind("/"))
self.last_shader_savepath = path self.last_shader_savepath = path
store_last_opened_file()
func save_shader(path: String): func save_shader(path: String):
print("Save ", path) print("Save ", path)
var file = FileAccess.open(path, FileAccess.WRITE) var file = FileAccess.open(path, FileAccess.WRITE)
file.store_string(self.shader_code) file.store_string(self.shader_code)
file.flush()
if "/" in path: # update current working directory if "/" in path: # update current working directory
self.cwd = path.substr(0, path.rfind("/")) self.cwd = path.substr(0, path.rfind("/"))
self.last_shader_savepath = path self.last_shader_savepath = path
store_last_opened_file()
func store_last_opened_file():
var f = FileAccess.open("user://last_opened", FileAccess.WRITE)
if f != null:
f.store_pascal_string(last_shader_savepath)
f.flush()
func remember_last_opened_file():
var f = FileAccess.open("user://last_opened", FileAccess.READ)
if f != null:
last_shader_savepath = f.get_pascal_string()

View file

@ -1,6 +1,7 @@
extends Node extends Node
@onready var editor_window = %EditorWindow @onready var editor_window = %EditorWindow
@onready var ui_container = %UserInterfaceContainer
@onready var app_name = ProjectSettings.get_setting("application/config/name") @onready var app_name = ProjectSettings.get_setting("application/config/name")
func _ready(): func _ready():
@ -11,6 +12,10 @@ func _ready():
editor_window.position.y) editor_window.position.y)
get_window().min_size = Vector2i(400, 400) get_window().min_size = Vector2i(400, 400)
editor_window.min_size = Vector2i(560, 400) editor_window.min_size = Vector2i(560, 400)
# Load last opened file
Filesystem.remember_last_opened_file()
if Filesystem.last_shader_savepath != "":
ui_container.get_node("Editor")._on_open_shader_dialog_file_selected(Filesystem.last_shader_savepath)
func update_title(current_file: String = ""): func update_title(current_file: String = ""):
if current_file == "": if current_file == "":