| export const description = "Video swipe"; | |
| export const help = "This transition performs simple 2D affine transformations for source videos transitions, with configurable effect origin"; | |
| export const options = [ | |
| {name:"from", value: "left", desc: `direction of video 2 entry. Possible values are: | |
| - left: from left to right edges | |
| - right: from right to left edges | |
| - top: from top to bottom edges | |
| - bottom: from bottom to top edges | |
| - topleft: from top-left to bottom-right corners | |
| - topright: from top-right to bottom-left corners | |
| - bottomleft: from bottom-left to top-right corners | |
| - bottomright: from bottom-right to top-left corners | |
| `}, | |
| {name:"mode", value: "slide", desc: `how video 2 entry impacts video 1. Possible values are: | |
| - slide: video 1 position is not modified | |
| - push: video 2 pushes video 1 away | |
| - squeeze: video 2 squeezes video 1 along opposite edge | |
| - grow: video 2 size increases, video 1 not modified | |
| - swap: video 2 size increases, video 1 size decreases | |
| `}, | |
| {} | |
| ]; | |
| export function load() { return { | |
| h_mode: 0, | |
| v_mode: 0, | |
| mod: 0, | |
| setup: function() | |
| { | |
| if (this.mode == "push") this.mod = 1; | |
| else if (this.mode == "squeeze") this.mod = 2; | |
| else if (this.mode == "grow") this.mod = 3; | |
| else if (this.mode == "swap") this.mod = 4; | |
| else this.mod = 0; | |
| this.h_mode = 0; | |
| this.v_mode = 0; | |
| if (this.from == "left") this.h_mode = 1; | |
| else if (this.from == "right") this.h_mode = 2; | |
| else if (this.from == "top") this.v_mode = 1; | |
| else if (this.from == "bottom") this.v_mode = 2; | |
| else if (this.from == "topleft") { | |
| this.h_mode = 1; | |
| this.v_mode = 1; | |
| } | |
| else if (this.from == "topright") { | |
| this.h_mode = 2; | |
| this.v_mode = 1; | |
| } | |
| else if (this.from == "bottomleft") { | |
| this.h_mode = 1; | |
| this.v_mode = 2; | |
| } | |
| else if (this.from == "bottomright") { | |
| this.h_mode = 2; | |
| this.v_mode = 2; | |
| } | |
| }, | |
| apply: function(canvas, ratio, path, pids) | |
| { | |
| if (use_gpu) { | |
| this.apply_gl(canvas, ratio, path, pids); | |
| return; | |
| } | |
| let rc = path.bounds; | |
| if (typeof rc == 'undefined') return; | |
| let new_w = rc.w; | |
| let new_h = rc.h; | |
| let new_x = 0; | |
| let new_y = 0; | |
| //left | |
| if (this.h_mode == 1) { | |
| new_x = -rc.w/2 + rc.w*ratio/2; | |
| new_w = rc.w*ratio; | |
| } | |
| //right | |
| else if (this.h_mode == 2) { | |
| new_x = rc.w/2 - rc.w*ratio/2; | |
| new_w = rc.w*ratio; | |
| } | |
| //top | |
| if (this.v_mode==1) { | |
| new_y = rc.h/2 - rc.h*ratio/2; | |
| new_h = rc.h*ratio; | |
| } | |
| //bottom | |
| else if (this.v_mode==2) { | |
| new_y = -rc.h/2 + rc.h*ratio/2; | |
| new_h = rc.h*ratio; | |
| } | |
| let new_path = path.clone(); | |
| //add rectangle to path | |
| new_path.rectangle(new_x, new_y, new_w, new_h, true); | |
| //use zero-nonzero fill | |
| new_path.zero_fill = true; | |
| if (! this.mod) { | |
| canvas.path = new_path; | |
| canvas.fill(GF_EVG_OPERAND_ODD_FILL, ratio, pids[0].texture, pids[1].texture); | |
| return; | |
| } | |
| let mx1_bck = pids[0].texture.mx; | |
| let mx2_bck = pids[1].texture.mx; | |
| let mx1 = mx1_bck.copy(); | |
| let mx2 = mx2_bck.copy(); | |
| let t_x1 = 0; | |
| let t_y1 = 0; | |
| let t_x2 = 0; | |
| let t_y2 = 0; | |
| let c_x1 = 0.5; | |
| let c_y1 = 0.5; | |
| let c_x2 = 0.5; | |
| let c_y2 = 0.5; | |
| //left | |
| if (this.h_mode==1) { | |
| t_x1 = ratio; | |
| c_x1 -= 0.5; | |
| t_x2 = (ratio-1); | |
| c_x2 += 0.5; | |
| } | |
| //right | |
| else if (this.h_mode==2) { | |
| t_x1 = -ratio; | |
| c_x1 += 0.5; | |
| t_x2 = -(ratio-1); | |
| c_x2 -= 0.5; | |
| } | |
| //top | |
| if (this.v_mode==1) { | |
| t_y1 = -ratio; | |
| c_y1 -= 0.5; | |
| t_y2 = -(ratio-1); | |
| c_y2 += 0.5; | |
| } | |
| //bottom | |
| else if (this.v_mode==2) { | |
| t_y1 = ratio; | |
| c_y1 += 0.5; | |
| t_y2 = (ratio-1); | |
| c_y2 -= 0.5; | |
| } | |
| mx1.translate(-t_x1, t_y1); | |
| mx2.translate(-t_x2, t_y2); | |
| if ((this.mod == 2) || (this.mod == 4)) { | |
| mx1.translate(-c_x1, -c_y1); | |
| mx1.scale( 1 / (1-ratio), 1/(1-ratio) ); | |
| mx1.translate(c_x1, c_y1); | |
| } | |
| if ((this.mod == 3) || (this.mod == 4)) { | |
| mx2.translate(-c_x2, -c_y2); | |
| mx2.scale(1/ratio, 1/ratio); | |
| mx2.translate(c_x2, c_y2); | |
| } | |
| let pad1_bck = pids[0].texture.get_pad_color(); | |
| let pad2_bck = pids[1].texture.get_pad_color(); | |
| let pad_col = pad1_bck || pad2_bck || 'black'; | |
| //pad with the same color ! | |
| pids[0].texture.set_pad_color(pad_col); | |
| pids[1].texture.set_pad_color(pad_col); | |
| pids[0].texture.mx = mx1; | |
| pids[1].texture.mx = mx2; | |
| canvas.path = new_path; | |
| canvas.fill(GF_EVG_OPERAND_ODD_FILL, ratio, pids[0].texture, pids[1].texture); | |
| pids[0].texture.set_pad_color(pad1_bck); | |
| pids[1].texture.set_pad_color(pad2_bck); | |
| pids[0].texture.mx = mx1_bck; | |
| pids[1].texture.mx = mx2_bck; | |
| }, | |
| pad_col_uni: null, | |
| pad_col: null, | |
| setup_gl: function(webgl, program, first_available_texture_unit) | |
| { | |
| this.pad_col_uni = webgl.getUniformLocation(program, 'swipe_pad_color'); | |
| this.pad_col = null; | |
| }, | |
| apply_gl: function(webgl, ratio, path, pids) | |
| { | |
| if (!this.pad_col_uni) return; | |
| let pad1_bck = pids[0].texture.get_pad_color() || 'black'; | |
| if (this.pad_col !== pad1_bck) { | |
| let a = sys.color_component(pad1_bck, 0); | |
| let r = sys.color_component(pad1_bck, 1); | |
| let g = sys.color_component(pad1_bck, 2); | |
| let b = sys.color_component(pad1_bck, 3); | |
| webgl.uniform4f(this.pad_col_uni, r, g, b, a); | |
| this.pad_col = pad1_bck; | |
| } | |
| }, | |
| get_shader_src: function() | |
| { | |
| this.setup(); | |
| let frag_src = `vec4 gf_apply_effect() { | |
| vec2 p = txcoord_from.xy; | |
| vec2 p_to = txcoord_to.xy; | |
| `; | |
| if (this.mod==0) { | |
| frag_src += ` | |
| vec2 txcf = p; | |
| vec2 txct = p_to; | |
| `; | |
| } | |
| let use_pad = false; | |
| if (this.h_mode == 1) { | |
| //topleft | |
| if (this.v_mode == 1) { | |
| frag_src += 'float myratio = step(0.0 + p.x, ratio) * step(0.0 + p.y, ratio);'; | |
| if (this.mod) { | |
| use_pad = true; | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x - ratio, p.y - ratio); | |
| vec2 txct = vec2(1.0 + p_to.x - ratio, 1.0 + p_to.y - ratio); | |
| float is_in = (myratio==0.0) ? step(1.0, txct.x) * step(1.0, txct.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf /= (1.0-ratio); | |
| is_in *= (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| frag_src += ` | |
| txct.x -= 1.0; | |
| txct.y -= 1.0; | |
| txct /= ratio; | |
| txct.x += 1.0; | |
| txct.y += 1.0; | |
| is_in *= (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| //bottomleft | |
| else if (this.v_mode == 2) { | |
| frag_src += 'float myratio = step(0.0 + p.x, ratio) * step(1.0 - p.y, ratio);'; | |
| if (this.mod) { | |
| use_pad = true; | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x - ratio, p.y + ratio); | |
| vec2 txct = vec2(1.0 + p_to.x - ratio, p_to.y + ratio - 1.0); | |
| float is_in = (myratio==0.0) ? step(1.0, txct.x) * step(txct.y, 0.0) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf.y -= 1.0; | |
| txcf /= (1.0-ratio); | |
| txcf.y += 1.0; | |
| is_in *= (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| frag_src += ` | |
| txct.x -= 1.0; | |
| txct /= ratio; | |
| txct.x += 1.0; | |
| is_in *= (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| //left | |
| else { | |
| frag_src += 'float myratio = step(0.0 + p.x, ratio);'; | |
| if (this.mod) { | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x - ratio, p.y); | |
| vec2 txct = vec2(1.0 + p_to.x - ratio, p_to.y); | |
| `; | |
| } | |
| if (this.mod>1) { | |
| frag_src += ` | |
| float is_in; | |
| `; | |
| use_pad = true; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf.y -= 0.5; | |
| txcf /= (1.0-ratio); | |
| txcf.y += 0.5; | |
| is_in = (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| let op = (this.mod==4) ? '*=' : '='; | |
| frag_src += ` | |
| txct.x -= 1.0; | |
| txct.y -= 0.5; | |
| txct /= ratio; | |
| txct.x += 1.0; | |
| txct.y += 0.5; | |
| is_in `+ op + ` (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| } | |
| else if (this.h_mode == 2) { | |
| //topright | |
| if (this.v_mode == 1) { | |
| frag_src += 'float myratio = step(1.0 - p.x, ratio) * step(0.0 + p.y, ratio);'; | |
| if (this.mod) { | |
| use_pad = true; | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x + ratio, p.y - ratio); | |
| vec2 txct = vec2(p_to.x + ratio - 1.0, 1.0 + p_to.y - ratio); | |
| float is_in = (myratio==0.0) ? step(txct.x, 0.0) * step(1.0, txct.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf.x -= 1.0; | |
| txcf /= (1.0-ratio); | |
| txcf.x += 1.0; | |
| is_in *= (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| frag_src += ` | |
| txct.y -= 1.0; | |
| txct /= ratio; | |
| txct.y += 1.0; | |
| is_in *= (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| //bottomright | |
| else if (this.v_mode == 2) { | |
| frag_src += 'float myratio = step(1.0 - p.x, ratio) * step(1.0 - p.y, ratio);'; | |
| if (this.mod) { | |
| use_pad = true; | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x + ratio, p.y + ratio); | |
| vec2 txct = vec2(p_to.x + ratio - 1.0, p_to.y + ratio - 1.0); | |
| float is_in = (myratio==0.0) ? step(txct.x, 0.0) * step(txct.y, 0.0) : 1.0; | |
| `; | |
| } | |
| if (this.mod==2) { | |
| frag_src += ` | |
| txcf.x -= 1.0; | |
| txcf.y -= 1.0; | |
| txcf /= (1.0-ratio); | |
| txcf.x += 1.0; | |
| txcf.y += 1.0; | |
| is_in *= (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| `; | |
| } | |
| if (this.mod==3) { | |
| frag_src += ` | |
| txct /= ratio; | |
| is_in *= (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| if (this.mod==4) { | |
| frag_src += ` | |
| txcf.x -= 1.0; | |
| txcf.y -= 1.0; | |
| txcf /= (1.0-ratio); | |
| txcf.x += 1.0; | |
| txcf.y += 1.0; | |
| is_in *= (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| txct /= ratio; | |
| is_in *= (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| //right | |
| else { | |
| frag_src += 'float myratio = step(1.0 - p.x, ratio);'; | |
| if (this.mod) { | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x + ratio, p.y); | |
| vec2 txct = vec2(p_to.x + ratio - 1.0, p_to.y); | |
| `; | |
| } | |
| if (this.mod>1) { | |
| frag_src += ` | |
| float is_in; | |
| `; | |
| use_pad = true; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf.x -= 1.0; | |
| txcf.y -= 0.5; | |
| txcf /= (1.0-ratio); | |
| txcf.x += 1.0; | |
| txcf.y += 0.5; | |
| is_in = (myratio==0.0) ? step(txcf.y, 1.0) * step(0.0, txcf.y) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| let op = (this.mod==4) ? '*=' : '='; | |
| frag_src += ` | |
| txct.y -= 0.5; | |
| txct /= ratio; | |
| txct.y += 0.5; | |
| is_in `+ op + ` (myratio>0.0) ? step(0.0, txct.y) * step(txct.y, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| } | |
| //top | |
| else if (this.v_mode == 1) { | |
| frag_src += 'float myratio = step(0.0 + p.y, ratio);'; | |
| if (this.mod) { | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x, p.y - ratio); | |
| vec2 txct = vec2(p_to.x, 1.0 + p_to.y - ratio); | |
| `; | |
| } | |
| if (this.mod>1) { | |
| frag_src += ` | |
| float is_in; | |
| `; | |
| use_pad = true; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf.x -= 0.5; | |
| txcf /= (1.0-ratio); | |
| txcf.x += 0.5; | |
| is_in = (myratio==0.0) ? step(0.0, txcf.x) * step(txcf.x, 1.0) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| let op = (this.mod==4) ? '*=' : '='; | |
| frag_src += ` | |
| txct.x -= 0.5; | |
| txct.y -= 1.0; | |
| txct /= ratio; | |
| txct.x += 0.5; | |
| txct.y += 1.0; | |
| is_in ` + op +` (myratio>0.0) ? step( 0.0, txct.x) * step(txct.x, 1.0) : 1.0; | |
| `; | |
| } | |
| } | |
| //bottom | |
| else if (this.v_mode == 2) { | |
| frag_src += 'float myratio = step(1.0 - p.y, ratio);'; | |
| if (this.mod) { | |
| frag_src += ` | |
| vec2 txcf = vec2(p.x, p.y + ratio); | |
| vec2 txct = vec2(p_to.x, p_to.y + ratio - 1.0); | |
| `; | |
| } | |
| if (this.mod>1) { | |
| frag_src += ` | |
| float is_in; | |
| `; | |
| use_pad = true; | |
| } | |
| if ((this.mod==2) || (this.mod==4)) { | |
| frag_src += ` | |
| txcf.x -= 0.5; | |
| txcf.y -= 1.0; | |
| txcf /= (1.0-ratio); | |
| txcf.x += 0.5; | |
| txcf.y += 1.0; | |
| is_in = (myratio==0.0) ? step(0.0, txcf.x) * step(txcf.x, 1.0) : 1.0; | |
| `; | |
| } | |
| if ((this.mod==3) || (this.mod==4)) { | |
| let op = (this.mod==4) ? '*=' : '='; | |
| frag_src += ` | |
| txct.x -= 0.5; | |
| txct /= ratio; | |
| txct.x += 0.5; | |
| is_in `+ op + `(myratio>0.0) ? step( 0.0, txct.x) * step(txct.x, 1.0) : 1.0; | |
| `; | |
| } | |
| } else { | |
| frag_src += 'float myratio = ratio;'; | |
| } | |
| frag_src += ` | |
| vec4 col_from = get_pixel_from(txcf.xy); | |
| vec4 col_to = get_pixel_to(txct.xy);`; | |
| if (use_pad) { | |
| frag_src += ` | |
| is_in = (is_in==0.0) ? 0.0 : 1.0; | |
| return mix(swipe_pad_color, mix(col_from, col_to, myratio), is_in); | |
| }`; | |
| } else { | |
| frag_src += ` | |
| return mix(col_from, col_to, myratio); | |
| }`; | |
| } | |
| if (use_pad) { | |
| frag_src = 'uniform vec4 swipe_pad_color;\n' + frag_src; | |
| } | |
| return frag_src; | |
| } | |
| }; } |