added blend modes

This commit is contained in:
2025-07-20 22:14:42 +10:00
parent ef8ecb3732
commit 43dfc410dc
10 changed files with 242 additions and 6 deletions

View File

@@ -0,0 +1,122 @@
shader_type canvas_item;
uniform float opacity : hint_range(0.0, 1.0) = 1.0;
uniform int blend_mode : hint_range(0, 11) = 0;
// Blend mode constants:
// 0: Normal
// 1: Multiply
// 2: Screen
// 3: Overlay
// 4: Soft Light
// 5: Hard Light
// 6: Color Dodge
// 7: Color Burn
// 8: Darken
// 9: Lighten
// 10: Add (Linear Dodge)
// 11: Subtract
vec3 multiply_blend(vec3 base, vec3 overlay) {
return base * overlay;
}
vec3 screen_blend(vec3 base, vec3 overlay) {
return 1.0 - (1.0 - base) * (1.0 - overlay);
}
vec3 overlay_blend(vec3 base, vec3 overlay) {
vec3 result;
result.r = base.r < 0.5 ? 2.0 * base.r * overlay.r : 1.0 - 2.0 * (1.0 - base.r) * (1.0 - overlay.r);
result.g = base.g < 0.5 ? 2.0 * base.g * overlay.g : 1.0 - 2.0 * (1.0 - base.g) * (1.0 - overlay.g);
result.b = base.b < 0.5 ? 2.0 * base.b * overlay.b : 1.0 - 2.0 * (1.0 - base.b) * (1.0 - overlay.b);
return result;
}
vec3 soft_light_blend(vec3 base, vec3 overlay) {
vec3 result;
result.r = overlay.r < 0.5 ? 2.0 * base.r * overlay.r + base.r * base.r * (1.0 - 2.0 * overlay.r) :
sqrt(base.r) * (2.0 * overlay.r - 1.0) + 2.0 * base.r * (1.0 - overlay.r);
result.g = overlay.g < 0.5 ? 2.0 * base.g * overlay.g + base.g * base.g * (1.0 - 2.0 * overlay.g) :
sqrt(base.g) * (2.0 * overlay.g - 1.0) + 2.0 * base.g * (1.0 - overlay.g);
result.b = overlay.b < 0.5 ? 2.0 * base.b * overlay.b + base.b * base.b * (1.0 - 2.0 * overlay.b) :
sqrt(base.b) * (2.0 * overlay.b - 1.0) + 2.0 * base.b * (1.0 - overlay.b);
return result;
}
vec3 hard_light_blend(vec3 base, vec3 overlay) {
vec3 result;
result.r = overlay.r < 0.5 ? 2.0 * base.r * overlay.r : 1.0 - 2.0 * (1.0 - base.r) * (1.0 - overlay.r);
result.g = overlay.g < 0.5 ? 2.0 * base.g * overlay.g : 1.0 - 2.0 * (1.0 - base.g) * (1.0 - overlay.g);
result.b = overlay.b < 0.5 ? 2.0 * base.b * overlay.b : 1.0 - 2.0 * (1.0 - base.b) * (1.0 - overlay.b);
return result;
}
vec3 color_dodge_blend(vec3 base, vec3 overlay) {
vec3 result;
result.r = overlay.r >= 1.0 ? 1.0 : min(1.0, base.r / (1.0 - overlay.r));
result.g = overlay.g >= 1.0 ? 1.0 : min(1.0, base.g / (1.0 - overlay.g));
result.b = overlay.b >= 1.0 ? 1.0 : min(1.0, base.b / (1.0 - overlay.b));
return result;
}
vec3 color_burn_blend(vec3 base, vec3 overlay) {
vec3 result;
result.r = overlay.r <= 0.0 ? 0.0 : max(0.0, 1.0 - (1.0 - base.r) / overlay.r);
result.g = overlay.g <= 0.0 ? 0.0 : max(0.0, 1.0 - (1.0 - base.g) / overlay.g);
result.b = overlay.b <= 0.0 ? 0.0 : max(0.0, 1.0 - (1.0 - base.b) / overlay.b);
return result;
}
vec3 darken_blend(vec3 base, vec3 overlay) {
return min(base, overlay);
}
vec3 lighten_blend(vec3 base, vec3 overlay) {
return max(base, overlay);
}
vec3 add_blend(vec3 base, vec3 overlay) {
return min(vec3(1.0), base + overlay);
}
vec3 subtract_blend(vec3 base, vec3 overlay) {
return max(vec3(0.0), base - overlay);
}
void fragment() {
vec4 tex_color = texture(TEXTURE, UV);
// Apply blend mode (only to RGB, preserve alpha channel behavior)
vec3 final_color;
if (blend_mode == 0) { // Normal
final_color = tex_color.rgb;
} else if (blend_mode == 1) { // Multiply
final_color = multiply_blend(vec3(1.0), tex_color.rgb);
} else if (blend_mode == 2) { // Screen
final_color = screen_blend(vec3(0.0), tex_color.rgb);
} else if (blend_mode == 3) { // Overlay
final_color = overlay_blend(vec3(0.5), tex_color.rgb);
} else if (blend_mode == 4) { // Soft Light
final_color = soft_light_blend(vec3(0.5), tex_color.rgb);
} else if (blend_mode == 5) { // Hard Light
final_color = hard_light_blend(vec3(0.5), tex_color.rgb);
} else if (blend_mode == 6) { // Color Dodge
final_color = color_dodge_blend(vec3(0.0), tex_color.rgb);
} else if (blend_mode == 7) { // Color Burn
final_color = color_burn_blend(vec3(1.0), tex_color.rgb);
} else if (blend_mode == 8) { // Darken
final_color = darken_blend(vec3(1.0), tex_color.rgb);
} else if (blend_mode == 9) { // Lighten
final_color = lighten_blend(vec3(0.0), tex_color.rgb);
} else if (blend_mode == 10) { // Add (Linear Dodge)
final_color = add_blend(vec3(0.0), tex_color.rgb);
} else if (blend_mode == 11) { // Subtract
final_color = subtract_blend(vec3(1.0), tex_color.rgb);
} else {
final_color = tex_color.rgb;
}
COLOR = vec4(final_color, tex_color.a * opacity);
}

View File

@@ -0,0 +1 @@
uid://dy03x5g364v80

View File

@@ -28,7 +28,7 @@ var imageSize = Vector2.ZERO
@onready var wob = $WobbleOrigin
@onready var outlineScene = preload("res://ui_scenes/selectedSprite/outline.tscn")
@onready var opacityShader = preload("res://ui_scenes/selectedSprite/opacity.gdshader")
@onready var opacityBlendShader = preload("res://ui_scenes/selectedSprite/opacity_blend.gdshader")
var opacityMaterial = null
@@ -90,6 +90,7 @@ var time = 0.0 # Time accumulator for physics calculations
#Opacity
var spriteOpacity = 1.0
var affectChildrenOpacity = false
var blendMode = 0 # Default to Normal blend mode
#Vis toggle
var toggle = "null"
@@ -517,14 +518,21 @@ func updateShaderOpacity():
var editorAlpha = sprite.modulate.a
var finalOpacity = totalOpacity * editorAlpha
# Always apply the opacity shader to ensure it's loaded
# Always apply the opacity blend shader to ensure it's loaded
if opacityMaterial == null:
opacityMaterial = ShaderMaterial.new()
opacityMaterial.shader = opacityShader
opacityMaterial.shader = opacityBlendShader
opacityMaterial.set_shader_parameter("opacity", finalOpacity)
opacityMaterial.set_shader_parameter("blend_mode", blendMode)
sprite.material = opacityMaterial
## Update the blend mode and refresh the shader
func updateBlendMode(newBlendMode: int):
if BlendModeManager.is_valid_blend_mode(newBlendMode):
blendMode = newBlendMode
updateShaderOpacity() # Refresh shader with new blend mode
func updateChildrenOpacityRecursively():
var linkedSprites = getAllLinkedSprites()
for child in linkedSprites:

View File

@@ -10,6 +10,7 @@ extends Node2D
@onready var coverCollider = $Area2D/CollisionShape2D
@onready var wobbleSyncControl = null # Will be assigned in _ready()
@onready var blendModeDropdown = $Opacity/blendModeDropdown
func _ready():
Global.spriteEdit = self
@@ -19,6 +20,9 @@ func _ready():
if wobbleSyncControl == null:
print("Warning: WobbleSyncControl node not found in sprite viewer")
# Set up blend mode dropdown
setupBlendModeDropdown()
func setImage():
if Global.heldSprite == null:
return
@@ -81,6 +85,7 @@ func setImage():
$Opacity/opacityLabel.text = "opacity: " + str(int(Global.heldSprite.spriteOpacity * 100)) + "%"
$Opacity/opacitySlider.value = Global.heldSprite.spriteOpacity
$Opacity/affectChildrenCheck.button_pressed = Global.heldSprite.affectChildrenOpacity
$Opacity/blendModeDropdown.selected = Global.heldSprite.blendMode
$VisToggle/setToggle/Label.text = "toggle: \"" + Global.heldSprite.toggle + "\""
@@ -449,3 +454,16 @@ func _on_opacity_slider_value_changed(value):
func _on_affect_children_check_toggled(button_pressed):
Global.heldSprite.affectChildrenOpacity = button_pressed
Global.heldSprite.updateOpacity()
## Set up the blend mode dropdown with all available blend modes
func setupBlendModeDropdown():
blendModeDropdown.clear()
var blendModeNames = BlendModeManager.get_blend_mode_names()
for mode_name in blendModeNames:
blendModeDropdown.add_item(mode_name)
## Handle blend mode dropdown selection
func _on_blend_mode_dropdown_item_selected(index: int):
if Global.heldSprite != null:
Global.heldSprite.updateBlendMode(index)
Global.pushUpdate("Blend mode set to: " + BlendModeManager.get_blend_mode_name(index))

View File

@@ -30,7 +30,7 @@
[ext_resource type="Texture2D" uid="uid://gflmeocxfnrq" path="res://ui_scenes/settings/deleteHotkey.png" id="27_fgu6g"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_21kva"]
size = Vector2(245, 1550)
size = Vector2(245, 1597)
[sub_resource type="ShaderMaterial" id="ShaderMaterial_hxmah"]
shader = ExtResource("3_ky0lu")
@@ -14286,7 +14286,7 @@ script = ExtResource("1_hp0e3")
z_index = -2
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
position = Vector2(122.5, 775)
position = Vector2(122.5, 798.5)
shape = SubResource("RectangleShape2D_21kva")
[node name="Border" type="Sprite2D" parent="."]
@@ -14768,6 +14768,20 @@ offset_right = 200.0
offset_bottom = 1166.0
theme = SubResource("Theme_mrbyn")
[node name="blendModeLabel" type="Label" parent="Opacity"]
offset_left = 11.0
offset_top = 2152.0
offset_right = 159.0
offset_bottom = 2178.0
text = "blend mode:"
[node name="blendModeDropdown" type="OptionButton" parent="Opacity"]
offset_left = 10.0
offset_top = 2173.0
offset_right = 233.0
offset_bottom = 2193.0
theme = SubResource("Theme_mrbyn")
[node name="Layers" type="Node2D" parent="."]
position = Vector2(0, 538)
@@ -14974,6 +14988,7 @@ centered = false
[connection signal="value_changed" from="Animation/animSpeed" to="." method="_on_anim_speed_value_changed"]
[connection signal="value_changed" from="Opacity/opacitySlider" to="." method="_on_opacity_slider_value_changed"]
[connection signal="toggled" from="Opacity/affectChildrenCheck" to="." method="_on_affect_children_check_toggled"]
[connection signal="item_selected" from="Opacity/blendModeDropdown" to="." method="_on_blend_mode_dropdown_item_selected"]
[connection signal="pressed" from="Layers/Layer1/layerButton1" to="." method="_on_layer_button_1_pressed"]
[connection signal="pressed" from="Layers/Layer2/layerButton2" to="." method="_on_layer_button_2_pressed"]
[connection signal="pressed" from="Layers/Layer3/layerButton3" to="." method="_on_layer_button_3_pressed"]