Hello, I wrote a patch to include GIMP's soft light and screen overlay modes in Cinelerra. I was going to use them the other day and realized that they weren't in the drop down box, so I added them. I've test it on my computer with the X11, X11-XV, and X11-OpenGL drivers and the different color models, and it works well for me. I'm not sure if anybody else would find this useful; thought I'd at least post it here.
Images for:
./cinelerra/data/mode_{screen,softlight}.png
./plugins/suv/data/mode_ ...
./plugins/bluedottheme/data/ ...
./plugins/defaulttheme/data/ ...
http://www.floft.net/uploads/scripts/cinelerra/screen.png
http://www.floft.net/uploads/scripts/cinelerra/softlight.png
Formulas from:
http://www.pegtop.net/delphi/articles/blendmodes/
http://docs.gimp.org/en/gimp-concepts-layer-modes.html
Garrett
diff --git a/cinelerra/data/Makefile.am b/cinelerra/data/Makefile.am
index 58fbb8d..0a8d6dc 100644
--- a/cinelerra/data/Makefile.am
+++ b/cinelerra/data/Makefile.am
@@ -8,7 +8,9 @@ PNGS = \
mode_multiply.png \
mode_normal.png \
mode_replace.png \
- mode_subtract.png
+ mode_subtract.png \
+ mode_softlight.png \
+ mode_screen.png
# this rule creates the .o file from the concatenated PNGs
.data.$(OBJEXT):
diff --git a/cinelerra/overlayframe.C b/cinelerra/overlayframe.C
index 343bd5f..3b21171 100644
--- a/cinelerra/overlayframe.C
+++ b/cinelerra/overlayframe.C
@@ -102,7 +102,7 @@ OverlayFrame::~OverlayFrame()
#define BLEND_3(max, temp_type, type, chroma_offset) \
{ \
- temp_type r, g, b; \
+ temp_type r, g, b, maxp1; \
\
/* if(mode != TRANSFER_NORMAL) printf("BLEND mode = %d\n", mode); */ \
switch(mode) \
@@ -190,6 +190,38 @@ OverlayFrame::~OverlayFrame()
b = (b * opacity + output[2] * transparency) / max; \
break; \
} \
+ case TRANSFER_SOFTLIGHT: \
+ temp_type rt, gt, bt; \
+ if((float)max == 1.0) maxp1 = 1.0; \
+ else maxp1 = (temp_type)max + 1; \
+ rt = (temp_type)input1*(temp_type)output[0]/maxp1; \
+ gt = (temp_type)input2*(temp_type)output[1]/maxp1; \
+ bt = (temp_type)input3*(temp_type)output[2]/maxp1; \
+ r = rt+(temp_type)input1*(max-((max-(temp_type)input1)*(max-(temp_type)output[0])/maxp1)-rt)/maxp1; \
+ g = gt+(temp_type)input2*(max-((max-(temp_type)input2)*(max-(temp_type)output[1])/maxp1)-gt)/maxp1; \
+ b = bt+(temp_type)input3*(max-((max-(temp_type)input3)*(max-(temp_type)output[2])/maxp1)-bt)/maxp1; \
+ r = (r * opacity + (temp_type)output[0] * transparency) / max; \
+ g = (g * opacity + (temp_type)output[1] * transparency) / max; \
+ b = (b * opacity + (temp_type)output[2] * transparency) / max; \
+ break; \
+ case TRANSFER_SCREEN: \
+ if((float)max == 1.0) maxp1 = 1.0; \
+ else maxp1 = (temp_type)max + 1; \
+ r = max - ((max-(temp_type)input1)*(max-(temp_type)output[0])/maxp1); \
+ if(chroma_offset) \
+ { \
+ g = my_abs((temp_type)input2 - chroma_offset) > my_abs((temp_type)output[1] - chroma_offset) ? input2 : output[1]; \
+ b = my_abs((temp_type)input3 - chroma_offset) > my_abs((temp_type)output[2] - chroma_offset) ? input3 : output[2]; \
+ } \
+ else \
+ { \
+ g = max - ((max-(temp_type)input2)*(max-(temp_type)output[1])/maxp1); \
+ b = max - ((max-(temp_type)input3)*(max-(temp_type)output[2])/maxp1); \
+ } \
+ r = (r * opacity + (temp_type)output[0] * transparency) / max; \
+ g = (g * opacity + (temp_type)output[1] * transparency) / max; \
+ b = (b * opacity + (temp_type)output[2] * transparency) / max; \
+ break; \
case TRANSFER_REPLACE: \
r = input1; \
g = input2; \
@@ -223,7 +255,7 @@ OverlayFrame::~OverlayFrame()
// Blending equations are drastically different for 3 and 4 components
#define BLEND_4(max, temp_type, type, chroma_offset) \
{ \
- temp_type r, g, b, a; \
+ temp_type r, g, b, a, maxp1; \
temp_type pixel_opacity, pixel_transparency; \
temp_type output1 = output[0]; \
temp_type output2 = output[1]; \
@@ -323,6 +355,43 @@ OverlayFrame::~OverlayFrame()
a = input4 > output4 ? input4 : output4; \
break; \
} \
+ case TRANSFER_SOFTLIGHT: \
+ temp_type rt, gt, bt; \
+ if((float)max == 1.0) maxp1 = 1.0; \
+ else maxp1 = (temp_type)max + 1; \
+ rt = (temp_type)input1*(temp_type)output1/maxp1; \
+ gt = (temp_type)input2*(temp_type)output2/maxp1; \
+ bt = (temp_type)input3*(temp_type)output3/maxp1; \
+ r = rt+(temp_type)input1*(max-((max-(temp_type)input1)*(max-(temp_type)output1)/maxp1)-rt)/maxp1; \
+ g = gt+(temp_type)input2*(max-((max-(temp_type)input2)*(max-(temp_type)output2)/maxp1)-gt)/maxp1; \
+ b = bt+(temp_type)input3*(max-((max-(temp_type)input3)*(max-(temp_type)output3)/maxp1)-bt)/maxp1; \
+ r = (r * pixel_opacity + (temp_type)output1 * pixel_transparency) / max / max; \
+ g = (g * pixel_opacity + (temp_type)output2 * pixel_transparency) / max / max; \
+ b = (b * pixel_opacity + (temp_type)output3 * pixel_transparency) / max / max; \
+ a = input4 > output4 ? input4 : output4; \
+ break; \
+ case TRANSFER_SCREEN: \
+ if((float)max == 1.0) maxp1 = 1.0; \
+ else maxp1 = (temp_type)max + 1; \
+ r = max - ((max-(temp_type)input1)*(max-(temp_type)output1)/maxp1); \
+ if(chroma_offset) \
+ { \
+ g = my_abs((temp_type)input2 - chroma_offset) > my_abs((temp_type)output2 - chroma_offset) ? input2 : output2; \
+ b = my_abs((temp_type)input3 - chroma_offset) > my_abs((temp_type)output3 - chroma_offset) ? input3 : output3; \
+ } \
+ else \
+ { \
+ g = max - ((max-(temp_type)input2)*(max-(temp_type)output2)/maxp1); \
+ b = max - ((max-(temp_type)input3)*(max-(temp_type)output3)/maxp1); \
+ } \
+ /*r = (r * opacity + (temp_type)output1 * transparency) / max; \
+ g = (g * opacity + (temp_type)output2 * transparency) / max; \
+ b = (b * opacity + (temp_type)output3 * transparency) / max;*/ \
+ r = (r * pixel_opacity + (temp_type)output1 * pixel_transparency) / max / max; \
+ g = (g * pixel_opacity + (temp_type)output2 * pixel_transparency) / max / max; \
+ b = (b * pixel_opacity + (temp_type)output3 * pixel_transparency) / max / max; \
+ a = input4 > output4 ? input4 : output4; \
+ break; \
case TRANSFER_REPLACE: \
r = input1; \
g = input2; \
diff --git a/cinelerra/overlayframe.inc b/cinelerra/overlayframe.inc
index 1cc95a1..985fa50 100644
--- a/cinelerra/overlayframe.inc
+++ b/cinelerra/overlayframe.inc
@@ -24,15 +24,17 @@
// Modes
-#define TRANSFER_TYPES 7
+#define TRANSFER_TYPES 9
#define TRANSFER_NORMAL 0
#define TRANSFER_ADDITION 1
#define TRANSFER_SUBTRACT 2
#define TRANSFER_MULTIPLY 3
-#define TRANSFER_DIVIDE 4
+#define TRANSFER_DIVIDE 4
#define TRANSFER_REPLACE 5
#define TRANSFER_MAX 6
+#define TRANSFER_SOFTLIGHT 7
+#define TRANSFER_SCREEN 8
// Interpolation types
diff --git a/cinelerra/patchbay.C b/cinelerra/patchbay.C
index 67366e2..75b0f4b 100644
--- a/cinelerra/patchbay.C
+++ b/cinelerra/patchbay.C
@@ -176,6 +176,12 @@ int PatchBay::create_objects()
mode_icons[TRANSFER_MAX] = new BC_Pixmap(this,
mwindow->theme->get_image("mode_max"),
PIXMAP_ALPHA);
+ mode_icons[TRANSFER_SOFTLIGHT] = new BC_Pixmap(this,
+ mwindow->theme->get_image("mode_softlight"),
+ PIXMAP_ALPHA);
+ mode_icons[TRANSFER_SCREEN] = new BC_Pixmap(this,
+ mwindow->theme->get_image("mode_screen"),
+ PIXMAP_ALPHA);
add_subwindow(nudge_popup = new NudgePopup(mwindow, this));
nudge_popup->create_objects();
diff --git a/cinelerra/playback3d.C b/cinelerra/playback3d.C
index 2db905c..8e70f6e 100644
--- a/cinelerra/playback3d.C
+++ b/cinelerra/playback3d.C
@@ -155,6 +155,34 @@ static char *blend_divide_frag =
" gl_FragColor = vec4(result, max(gl_FragColor.a, canvas.a));\n"
"}\n";
+static char *blend_softlight_frag =
+ "uniform sampler2D tex2;\n"
+ "uniform vec2 tex2_dimensions;\n"
+ "void main()\n"
+ "{\n"
+ " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
+ " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
+ " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
+ " gl_FragColor.rgb = gl_FragColor.rgb * canvas.rgb + gl_FragColor.rgb * (1.0 - ((1.0 - gl_FragColor.rgb) * (1.0 - canvas.rgb)) - (gl_FragColor.rgb * canvas.rgb));\n"
+ " gl_FragColor.rgb *= opacity;\n"
+ " gl_FragColor.rgb += canvas.rgb * transparency;\n"
+ " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
+ "}\n";
+
+static char *blend_screen_frag =
+ "uniform sampler2D tex2;\n"
+ "uniform vec2 tex2_dimensions;\n"
+ "void main()\n"
+ "{\n"
+ " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n"
+ " vec3 opacity = vec3(gl_FragColor.a, gl_FragColor.a, gl_FragColor.a);\n"
+ " vec3 transparency = vec3(1.0, 1.0, 1.0) - opacity;\n"
+ " gl_FragColor.rgb = 1.0 - (1.0 - gl_FragColor.rgb) * (1.0 - canvas.rgb);\n"
+ " gl_FragColor.rgb *= opacity;\n"
+ " gl_FragColor.rgb += canvas.rgb * transparency;\n"
+ " gl_FragColor.a = max(gl_FragColor.a, canvas.a);\n"
+ "}\n";
+
static char *multiply_alpha_frag =
"void main()\n"
"{\n"
@@ -957,6 +985,16 @@ void Playback3D::overlay_sync(Playback3DCommand *command)
if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
shader_stack[total_shaders++] = blend_divide_frag;
break;
+ case TRANSFER_SOFTLIGHT:
+ enable_overlay_texture(command);
+ if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
+ shader_stack[total_shaders++] = blend_softlight_frag;
+ break;
+ case TRANSFER_SCREEN:
+ enable_overlay_texture(command);
+ if(!total_shaders) shader_stack[total_shaders++] = read_texture_frag;
+ shader_stack[total_shaders++] = blend_screen_frag;
+ break;
}
unsigned int frag_shader = 0;
diff --git a/cinelerra/theme.C b/cinelerra/theme.C
index dba3dc7..c829c35 100644
--- a/cinelerra/theme.C
+++ b/cinelerra/theme.C
@@ -133,6 +133,8 @@ void Theme::initialize()
new_image("mode_normal", "mode_normal.png");
new_image("mode_replace", "mode_replace.png");
new_image("mode_subtract", "mode_subtract.png");
+ new_image("mode_softlight", "mode_softlight.png");
+ new_image("mode_screen", "mode_screen.png");
}
diff --git a/cinelerra/vpatchgui.C b/cinelerra/vpatchgui.C
index f711e24..0d8b9b7 100644
--- a/cinelerra/vpatchgui.C
+++ b/cinelerra/vpatchgui.C
@@ -335,6 +335,8 @@ int VModePatch::create_objects()
add_item(new VModePatchItem(this, mode_to_text(TRANSFER_DIVIDE), TRANSFER_DIVIDE));
add_item(new VModePatchItem(this, mode_to_text(TRANSFER_REPLACE), TRANSFER_REPLACE));
add_item(new VModePatchItem(this, mode_to_text(TRANSFER_MAX), TRANSFER_MAX));
+ add_item(new VModePatchItem(this, mode_to_text(TRANSFER_SOFTLIGHT), TRANSFER_SOFTLIGHT));
+ add_item(new VModePatchItem(this, mode_to_text(TRANSFER_SCREEN), TRANSFER_SCREEN));
return 0;
}
@@ -380,6 +382,14 @@ char* VModePatch::mode_to_text(int mode)
case TRANSFER_MAX:
return _("Max");
break;
+
+ case TRANSFER_SOFTLIGHT:
+ return _("Soft Light");
+ break;
+
+ case TRANSFER_SCREEN:
+ return _("Screen");
+ break;
default:
return _("Normal");
diff --git a/plugins/bluedottheme/bluedottheme.C b/plugins/bluedottheme/bluedottheme.C
index e195d85..f081493 100644
--- a/plugins/bluedottheme/bluedottheme.C
+++ b/plugins/bluedottheme/bluedottheme.C
@@ -421,6 +421,8 @@ void BlueDotTheme::initialize()
new_image("mode_replace", "mode_replace.png");
new_image("mode_subtract", "mode_subtract.png");
new_image("mode_max", "mode_max.png");
+ new_image("mode_softlight", "mode_softlight.png");
+ new_image("mode_screen", "mode_screen.png");
//Graphic Copied from default. Improve!!
new_toggle("plugin_on.png",
diff --git a/plugins/defaulttheme/data/Makefile.am b/plugins/defaulttheme/data/Makefile.am
index 702a816..6716c7b 100644
--- a/plugins/defaulttheme/data/Makefile.am
+++ b/plugins/defaulttheme/data/Makefile.am
@@ -159,6 +159,8 @@ mode_multiply.png \
mode_normal.png \
mode_replace.png \
mode_subtract.png \
+mode_softlight.png \
+mode_screen.png \
mutepatch_checkedhi.png \
mutepatch_checked.png \
mutepatch_dn.png \
diff --git a/plugins/defaulttheme/defaulttheme.C b/plugins/defaulttheme/defaulttheme.C
index 793a945..5c63f65 100644
--- a/plugins/defaulttheme/defaulttheme.C
+++ b/plugins/defaulttheme/defaulttheme.C
@@ -389,6 +389,8 @@ void BlondTheme::initialize()
new_image("mode_replace", "mode_replace.png");
new_image("mode_subtract", "mode_subtract.png");
new_image("mode_max", "mode_max.png");
+ new_image("mode_softlight", "mode_softlight.png");
+ new_image("mode_screen", "mode_screen.png");
new_toggle("plugin_on.png",
"pluginbutton_hi.png",
diff --git a/plugins/overlay/overlay.C b/plugins/overlay/overlay.C
index 5c343f1..740fff5 100644
--- a/plugins/overlay/overlay.C
+++ b/plugins/overlay/overlay.C
@@ -204,6 +204,14 @@ char* OverlayConfig::mode_to_text(int mode)
case TRANSFER_MAX:
return "Max";
break;
+
+ case TRANSFER_SOFTLIGHT:
+ return "Soft Light";
+ break;
+
+ case TRANSFER_SCREEN:
+ return "Screen";
+ break;
default:
return "Normal";
@@ -590,6 +598,18 @@ int Overlay::handle_opengl()
" if(src_color.r == 0.0) result_color.r = 1.0;\n"
" if(src_color.g == 0.0) result_color.g = 1.0;\n"
" if(src_color.b == 0.0) result_color.b = 1.0;\n";
+
+ static char *blend_softlight_frag_float =
+ " result_color.rgb = dst_color.rgb*src_color.rgb+dst_color.rgb*(1.0-((1.0-dst_color.rgb)*(1.0-src_color.rgb))-(dst_color.rgb*src_color.rgb));\n";
+
+ static char *blend_softlight_frag =
+ " result_color.rgb = dst_color.rgb*src_color.rgb/256.0+dst_color.rgb*(255-((255-dst_color.rgb)*(255-src_color.rgb)/256)-(dst_color.rgb*src_color.rgb/256))/256;\n";
+
+ static char *blend_screen_frag_float =
+ " result_color.rgb = 1.0-(1.0-dst_color.rgb)*(1.0-src_color.rgb);\n";
+
+ static char *blend_screen_frag =
+ " result_color.rgb = 255-(255-dst_color.rgb)*(255-src_color.rgb)/256;\n";
VFrame *src = temp;
@@ -653,6 +673,7 @@ int Overlay::handle_opengl()
src->bind_texture(0);
dst->bind_texture(1);
+ int colormodel = dst->get_color_model();
shader_stack[current_shader++] = get_pixels_frag;
@@ -673,6 +694,18 @@ int Overlay::handle_opengl()
case TRANSFER_MAX:
shader_stack[current_shader++] = blend_max_frag;
break;
+ case TRANSFER_SOFTLIGHT:
+ if (colormodel == BC_RGB_FLOAT || colormodel == BC_RGBA_FLOAT)
+ shader_stack[current_shader++] = blend_softlight_frag_float;
+ else
+ shader_stack[current_shader++] = blend_softlight_frag;
+ break;
+ case TRANSFER_SCREEN:
+ if (colormodel == BC_RGB_FLOAT || colormodel == BC_RGBA_FLOAT)
+ shader_stack[current_shader++] = blend_screen_frag_float;
+ else
+ shader_stack[current_shader++] = blend_screen_frag;
+ break;
}
shader_stack[current_shader++] = put_pixels_frag;
diff --git a/plugins/suv/suv.C b/plugins/suv/suv.C
index 6a5a695..588a513 100644
--- a/plugins/suv/suv.C
+++ b/plugins/suv/suv.C
@@ -382,6 +382,8 @@ void SUV::initialize()
new_image("mode_replace", "mode_replace.png");
new_image("mode_subtract", "mode_subtract.png");
new_image("mode_max", "mode_max.png");
+ new_image("mode_softlight", "mode_softlight.png");
+ new_image("mode_screen", "mode_screen.png");
new_image_set("plugin_on", 5, "plugin_on.png", "plugin_onhi.png", "plugin_onselect.png", "plugin_ondn.png", "plugin_onselecthi.png");
new_image_set("plugin_show", 5, "plugin_show.png", "plugin_showhi.png", "plugin_showselect.png", "plugin_showdn.png", "plugin_showselecthi.png");
signature.asc
Description: PGP signature
