![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/hessa.corals.io/wp-content/plugins/trx_addons/addons/image-effects/ |
/* global jQuery, TRX_ADDONS_STORAGE */ (function() { "use strict"; // Settings var planeClassPrefix = 'trx_addons_image_effects_on_'; // class prefix of wrappers with image var globalCanvas = false; // true - one canvas for all images is used (twitches when scrolling the page), // false - separate canvas for each image is created (smooth scrolling, but WebKit limit: maximum of 16 objects per page) var permanentDrawing = globalCanvas || false; // true - permanent redraw images on canvas, // false - redraw only on ready and on hover var curtains = null; // global curtains object (used if globalCanvas is true) var $document = jQuery(document); var firstLoad = false; var sliderInited = false; window.addEventListener( 'load', function() { if ( typeof trx_addons_apply_filters == 'function' ) { globalCanvas = trx_addons_apply_filters( 'trx_addons_filter_image_effects_use_global_canvas', globalCanvas ); permanentDrawing = globalCanvas || false; } firstLoad = true; create_planes(); } ); function create_planes() { // not available in the edit mode of Elementor if ( typeof window.elementorFrontend !== 'undefined' && elementorFrontend.isEditMode() ) { return; } // exit if a module 'Curtains' is not available if ( typeof window.Curtains == 'undefined' ) { return; } // get our plane element var planeElements = document.querySelectorAll( '[class*="' + planeClassPrefix + '"]:not(.trx_addons_image_effects_inited)' + ( jQuery('body').hasClass( 'allow_lazy_load' ) ? '.lazyload_inited' : '' ) ); // exit if no image effects are present on the current page if ( planeElements.length === 0 ) return; // create global canvas and append it to the body if ( globalCanvas ) { curtains = create_canvas( document.body ); } // create planes and handle them trx_addons_when_images_loaded( jQuery( planeElements ), function() { var effect, total = 0; for (var i = 0; i < planeElements.length; i++) { if ( ! firstLoad && planeElements[i].closest( '.elementor-section-stretched' ) ) continue; if ( ! sliderInited && planeElements[i].closest( '.slider-slide' ) ) continue; total++; if ( ! planeElements[i].classList.contains( 'trx_addons_image_effects_inited' ) && jQuery( planeElements[i] ).parents(':hidden').length === 0 ) { effect = get_effect_name( planeElements[i] ); if ( effect && typeof window['trx_addons_image_effects_callback_' + effect] == 'function' ) { window['trx_addons_image_effects_callback_' + effect]( curtains, planeElements[i], i, planeElements.length ); planeElements[i].classList.add("trx_addons_image_effects_inited"); } } } // mark body as all planes are loaded if ( total === planeElements.length ) { document.body.classList.add("trx_addons_image_effects_planes_loaded"); $document.trigger('action.trx_addons_image_effects_inited', [planeElements]); } } ); } $document.on( 'action.got_ajax_response', function() { if ( firstLoad ) { create_planes(); } } ); $document.on( 'action.init_hidden_elements', function() { if ( firstLoad ) { create_planes(); } } ); $document.on( 'action.slider_inited', function() { if ( ! sliderInited ) { sliderInited = true; create_planes(); } } ); $document.on( 'action.init_lazy_load_elements', function( e, element ) { var parent = element.parents('[class*="trx_addons_image_effects_on_"]:not(.trx_addons_image_effects_inited)'); if ( parent.length > 0 ) { parent.addClass('lazyload_inited'); // Hide and load image parent.css({'opacity': 0, 'transition': 'opacity 0s ease'}); // Re-create canvas elements create_planes(); // Fade in image setTimeout(function(){ // Show loaded image parent.css({'opacity': 1, 'transition': 'opacity 0.3s ease'}); // Remove styles setTimeout(function(){ parent.css({'opacity': '', 'transition': ''}); }, 300); }, 100); } } ); $document.on('action.before_remove_content action.deactivate_tab', function(e, cont) { cont.find( '.trx_addons_image_effects_inited' ).each( function() { var $self = jQuery( this ), $canvas = $self.find('.trx_addons_image_effects_canvas'), curtains = $self.data('curtains'); if ( ! globalCanvas ) { if ( curtains ) { curtains.dispose(); curtains = null; $self.removeData( 'curtains' ); } } else { var plane = $self.data('curtains-plane'); if ( plane ) { curtains.removePlane( plane ); plane = null; $self.removeData('curtains-plane'); } } $canvas.remove(); }); }); $document.on('action.after_add_content action.activate_tab', function(e, cont) { cont.find( '.trx_addons_image_effects_inited' ).each( function() { jQuery( this ) .removeClass('trx_addons_image_effects_inited') .find( '[id^="trx_addons_image_effects_canvas_"]' ).remove().end() .find( '.trx_addons_image_effects_holder' ).removeClass('trx_addons_image_effects_holder').end(); }); }); // Utilities //------------------------------------------- // Return name of image effect for element function get_effect_name( elm ) { var name = ''; for ( var i=0; i < elm.classList.length; i++ ) { if ( elm.classList[i].indexOf(planeClassPrefix) === 0 ) { name = elm.classList[i].substring( planeClassPrefix.length ); break; } } return name; } // Return mouse coordinates relative to the current image function get_mouse_position_from_event( e ) { var mouse = {}; // touch event if (e.targetTouches) { mouse.x = globalCanvas ? e.targetTouches[0].clientX : e.targetTouches[0].layerX; mouse.y = globalCanvas ? e.targetTouches[0].clientY : e.targetTouches[0].layerY; // mouse event } else { // In Chrome with custom scroll mouse coordinates in layerXY are incorrect // but in Mozilla mouse properties offsetXY always empty (equal to 0) mouse.x = globalCanvas ? e.clientX : ( e.offsetX !== 0 || e.offsetY !== 0 ? e.offsetX : e.layerX ); mouse.y = globalCanvas ? e.clientY : ( e.offsetX !== 0 || e.offsetY !== 0 ? e.offsetY : e.layerY ); } return mouse; } // Convert our mouse/touch position to coordinates relative to the vertices of the plane function mouse_to_plane_coords( plane, mpos ) { var w = plane.htmlElement.clientWidth, cw = w / 2, h = plane.htmlElement.clientHeight, ch = h / 2; return { x: ( mpos.x - cw ) / cw, y: -( mpos.y - ch ) / ch }; } // Add canvas holder var total = 0; function create_canvas( item ) { // Append canvas holder to the item var id = 'trx_addons_image_effects_canvas_'+total++, div = document.createElement("div"); div.setAttribute('id', id); div.setAttribute('class', 'trx_addons_image_effects_canvas'); item.appendChild(div); // Set up our WebGL context and append the canvas to our wrapper var webGLCurtain = new Curtains({ watchScroll: globalCanvas, premultipliedAlpha: true, // to avoid gray edge on images in effects 'waves', 'smudge', etc. (who changes the image border geometry) container: id // if not specified - library create own canvas container }); // Handling errors webGLCurtain .onError(function() { // we will add a class to the document body to display original images document.body.classList.add("no-curtains", "trx_addons_image_effects_planes_loaded"); }) .onContextLost(function() { // on context lost, try to restore the context webGLCurtain.restoreContext(); }); return webGLCurtain; } // Effect 'Waves' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_waves = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; var waveForceMin = 0, waveForceMax = 7; var waveFactor = elm.getAttribute('data-image-effect-waves-factor') || 4; var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var paddingOnHover = typeof trx_addons_apply_filters == 'function' ? trx_addons_apply_filters( 'trx_addons_filter_image_effects_padding', 0.04, 'waves' ) : 0.04; var effectStrength = Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30.0 ) ); var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'wavesTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params() { var vs = ` #ifdef GL_ES precision mediump float; #endif // those are the mandatory attributes that the lib sets attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; // those are mandatory uniforms that the lib sets and that contain our model view and projection matrix uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrix uniform uniform mat4 wavesTextureMatrix; // if you want to pass your vertex and texture coords to the fragment shader varying vec3 vVertexPosition; varying vec2 vTextureCoord; // effect control vars declared inside our javascript uniform float uTime; uniform float uMouseMoveStrength; uniform float uEffectStrength; uniform float uWaveFactor; uniform vec2 uMousePosition; uniform float hoveringWaveForce; uniform float uPadding; void main() { vec3 vertexPosition = aVertexPosition; float distanceFromMouse = distance(uMousePosition, vec2(vertexPosition.x, vertexPosition.y)); float waveSinusoid = cos(uWaveFactor * (distanceFromMouse - (uTime / 75.0))); float distanceStrength = 0.4 / (distanceFromMouse + 0.4); float distortionEffect = distanceStrength * waveSinusoid * uMouseMoveStrength / uEffectStrength; vertexPosition.z += distortionEffect; vertexPosition.x += distortionEffect * (uMousePosition.x - vertexPosition.x) * hoveringWaveForce * 3.0; vertexPosition.y += distortionEffect * (uMousePosition.y - vertexPosition.y) * hoveringWaveForce; gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, (1.0 + uPadding)); vTextureCoord = (wavesTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // get our varying variables varying vec3 vVertexPosition; varying vec2 vTextureCoord; // our texture sampler uniform sampler2D wavesTexture; // effect control vars uniform float displacement; void main() { if ( false ) { float intensity = 1.0; vec2 textureCoord = vTextureCoord; vec4 image1 = texture2D(wavesTexture, textureCoord); vec4 image2 = texture2D(wavesTexture, textureCoord); vec4 texture1 = texture2D(wavesTexture, vec2(textureCoord.x, textureCoord.y + displacement * (image2 * intensity))); vec4 texture2 = texture2D(wavesTexture, vec2(textureCoord.x, textureCoord.y + (1.0 - displacement) * (image1 * intensity))); vec4 result = mix(texture1, texture2, displacement); gl_FragColor = result; } else { vec2 textureCoord = vTextureCoord; gl_FragColor = texture2D(wavesTexture, textureCoord); } } `; return { vertexShader: vs, fragmentShader: fs, widthSegments: 10, heightSegments: 10, uniforms: { time: { name: "uTime", type: "1f", value: 0 }, mousePosition: { name: "uMousePosition", type: "2f", value: [-.5, .5] }, mouseMoveStrength: { name: "uMouseMoveStrength", type: "1f", value: .2 }, effectStrength: { name: "uEffectStrength", type: "1f", value: effectStrength }, displacement: { name: "displacement", type: "1f", value: 0 }, waveFactor: { name: "uWaveFactor", type: "1f", value: waveFactor }, hoveringWaveForce: { name: "hoveringWaveForce", type: "1f", value: waveForceMin }, padding: { name: "uPadding", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { // console.log('Waves onLoading'); }) .onReady(function() { // console.log('Waves onReady: Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenForce = null; plane.tweenScale = null; plane.tweenPadding = null; // now that our plane is ready we can listen to mouse move event function mouse_move() { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_wave_force( waveForceMax ); change_scale( 1 ); if ( paddingOnHover ) { change_padding( paddingOnHover ); } } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_wave_force( waveForceMin ); change_scale( 0 ); if ( paddingOnHover ) { change_padding( 0 ); } } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { // if ( globalCanvas ) plane.updatePosition(); plane.uniforms.time.value++; }) .onAfterResize(function() { // console.log('Waves afterResize: Plane '+index+' of '+total+' is resized'); }); // Change wave force value function change_wave_force( to ) { if ( plane.tweenForce ) { trx_addons_tween_stop( plane.tweenForce ); } plane.tweenForce = trx_addons_tween_value( { start: plane.uniforms.hoveringWaveForce.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.hoveringWaveForce.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tweenForce ); plane.tweenForce = null; } } } ); } // Change padding value function change_padding( to ) { if ( plane.tweenPadding ) { trx_addons_tween_stop( plane.tweenPadding ); } plane.tweenPadding = trx_addons_tween_value( { start: plane.uniforms.padding.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.padding.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tweenPadding ); plane.tweenPadding = null; } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to === 0 ) { curtains.disableDrawing(); } } } } ); } } }; // Effect 'Waves2' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_waves2 = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; var waveForceMin = 0, waveForceMax = 2; var waveFactor = elm.getAttribute('data-image-effect-waves-factor') || 4; var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var paddingOnHover = typeof trx_addons_apply_filters == 'function' ? trx_addons_apply_filters( 'trx_addons_filter_image_effects_padding', 0.04, 'waves2' ) : 0.04; var effectStrength = Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30.0 ) ); var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'waves2Texture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params( elm, img, parent ) { var vs = ` #ifdef GL_ES precision mediump float; #endif // default mandatory variables attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrix uniform mat4 waves2TextureMatrix; // custom variables varying vec3 vVertexPosition; varying vec2 vTextureCoord; uniform float uTime; uniform vec2 uResolution; uniform vec2 uMousePosition; uniform float uMouseMoveStrength; uniform float uEffectStrength; uniform float uWaveFactor; uniform float uPadding; void main() { vec3 vertexPosition = aVertexPosition; // get the distance between our vertex and the mouse position float distanceFromMouse = distance(uMousePosition, vec2(vertexPosition.x, vertexPosition.y)); // calculate our wave effect float waveSinusoid = cos(uWaveFactor * (distanceFromMouse - (uTime / 75.0))); // attenuate the effect based on mouse distance float distanceStrength = 0.4 / (distanceFromMouse + 0.4); // calculate our distortion effect float distortionEffect = distanceStrength * waveSinusoid * uMouseMoveStrength / uEffectStrength; // apply it to our vertex position vertexPosition.z += distortionEffect; vertexPosition.x += distortionEffect * (uMousePosition.x - vertexPosition.x) * (uResolution.x / uResolution.y); vertexPosition.y += distortionEffect * (uMousePosition.y - vertexPosition.y); gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, (1.0 + uPadding)); // varyings vTextureCoord = (waves2TextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif varying vec3 vVertexPosition; varying vec2 vTextureCoord; uniform sampler2D waves2Texture; void main() { // apply our texture vec4 finalColor = texture2D(waves2Texture, vTextureCoord); // fake shadows based on vertex position along Z axis finalColor.rgb -= clamp(-vVertexPosition.z, 0.0, 1.0); // fake lights based on vertex position along Z axis finalColor.rgb += clamp(vVertexPosition.z, 0.0, 1.0); // handling premultiplied alpha (useful if we were using a png with transparency) finalColor = vec4(finalColor.rgb * finalColor.a, finalColor.a); gl_FragColor = finalColor; } `; return { vertexShader: vs, fragmentShader: fs, widthSegments: 20, heightSegments: 20, uniforms: { resolution: { // resolution of our plane name: "uResolution", type: "2f", // notice this is an length 2 array of floats value: [ parent.clientWidth, parent.clientHeight ] }, time: { // time uniform that will be updated at each draw call name: "uTime", type: "1f", value: 0 }, mousePosition: { // our mouse position name: "uMousePosition", type: "2f", // again an array of floats value: [-.5, .5] }, mouseMoveStrength: { // the mouse move strength name: "uMouseMoveStrength", type: "1f", value: 0 }, effectStrength: { // the effect strength name: "uEffectStrength", type: "1f", value: effectStrength }, waveFactor: { // waves frequency name: "uWaveFactor", type: "1f", value: waveFactor }, padding: { // padding around image on hover name: "uPadding", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { //console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // set a fov of 35 to reduce perspective plane.setPerspective(35); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tween = null; plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move() { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_wave_force( waveForceMax ); change_scale( 1 ); if ( paddingOnHover ) { change_padding( paddingOnHover ); } } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_wave_force( waveForceMin ); change_scale( 0 ); if ( paddingOnHover ) { change_padding( 0 ); } } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { // increment our time uniform plane.uniforms.time.value++; }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); /* Commented, because set width and height to 0 inside slider var planeBoundingRect = plane.getBoundingRect(); plane.uniforms.resolution.value = [ planeBoundingRect.width, planeBoundingRect.height ]; */ }); } // Change wave force value function change_wave_force( to ) { if ( plane.tween ) { trx_addons_tween_stop( plane.tween ); } plane.tween = trx_addons_tween_value( { start: plane.uniforms.mouseMoveStrength.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.mouseMoveStrength.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tween ); plane.tween = null } } } ); } // Change padding value function change_padding( to ) { if ( plane.tweenPadding ) { trx_addons_tween_stop( plane.tweenPadding ); } plane.tweenPadding = trx_addons_tween_value( { start: plane.uniforms.padding.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.padding.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tweenPadding ); plane.tweenPadding = null; } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to === 0 ) { curtains.disableDrawing(); } } } } ); } }; // Effect 'Ripple' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_ripple = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; // Common vars var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var effectStrength = Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30.0 ) ); // Effect-specific vars var wavesDirection = Math.max(0.0, Math.min(1.0, elm.getAttribute('data-image-effect-waves-direction') ) ); // Curtains init var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'rippleTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params() { var vs = ` #ifdef GL_ES precision mediump float; #endif // those are the mandatory attributes that the lib sets attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; // those are mandatory uniforms that the lib sets and that contain our model view and projection matrix uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrix uniform uniform mat4 rippleTextureMatrix; // if you want to pass your vertex and texture coords to the fragment shader varying vec3 vVertexPosition; varying vec2 vTextureCoord; void main() { // get the vertex position from its attribute vec3 vertexPosition = aVertexPosition; // set its position based on projection and model view matrix gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0); // set the varying variables // thanks to the texture matrix we will be able to calculate accurate texture coords // so that our texture will always fit our plane without being distorted vTextureCoord = (rippleTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // get our varying variables varying vec3 vVertexPosition; varying vec2 vTextureCoord; // our texture sampler uniform sampler2D rippleTexture; // effect control vars declared inside our javascript uniform float uTime; // time iterator to change waves position uniform float uEffectStrength; // 5.0 - 50.0 - waves amplitude uniform float uWavesForce; // 0.0 - 1.0 - fadeIn/fadeOut on mouse hover uniform float uWavesDirection; // 0 - horizontal, 1 - vertical void main() { // get our texture coords vec2 textureCoord = vTextureCoord; // displace our pixels along both axis based on our time uniform and texture UVs // this will create a kind of water surface effect // try to comment a line or change the constants to see how it changes the effect // reminder : textures coords are ranging from 0.0 to 1.0 on both axis const float PI = 3.141592; textureCoord.x += ( sin(textureCoord.x * 10.0 * ( 2.0 - uWavesDirection ) + ((uTime * (PI / 3.0)) * 0.031)) + sin(textureCoord.y * 10.0 * ( 2.0 - uWavesDirection ) + ((uTime * (PI / 2.489)) * 0.017)) ) / uEffectStrength / ( 2.5 + 1.5 * uWavesDirection ) * uWavesForce; // * 0.0075; textureCoord.y += ( sin(textureCoord.y * 20.0 / ( 2.0 - uWavesDirection ) + ((uTime * (PI / 2.023)) * 0.023)) + sin(textureCoord.x * 20.0 / ( 2.0 - uWavesDirection ) + ((uTime * (PI / 3.1254)) * 0.037)) ) / uEffectStrength / ( 2.5 + 1.5 * ( 1.0 - uWavesDirection ) ) * uWavesForce; // * 0.0125; gl_FragColor = texture2D(rippleTexture, textureCoord); } `; return { vertexShader: vs, // our vertex shader ID fragmentShader: fs, // our fragment shader ID // widthSegments: 10, // heightSegments: 10, uniforms: { // variables passed to shaders time: { name: "uTime", type: "1f", value: 0 }, effectStrength: { name: "uEffectStrength", type: "1f", value: effectStrength }, wavesForce: { name: "uWavesForce", type: "1f", value: 0 }, wavesDirection: { name: "uWavesDirection", type: "1f", value: wavesDirection } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { // console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenForce = null; plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_waves_force( 1 ); change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_waves_force( 0 ); change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { plane.uniforms.time.value++; }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); }); // Change wave force value function change_waves_force( to ) { if ( plane.tweenForce ) { trx_addons_tween_stop( plane.tweenForce ); } plane.tweenForce = trx_addons_tween_value( { start: plane.uniforms.wavesForce.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.wavesForce.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tweenForce ); plane.tweenForce = null; } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to === 0 ) { curtains.disableDrawing(); } } } } ); } } }; // Effect 'Ripple 2' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_ripple2 = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; // Common vars var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var effectStrength = Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30.0 ) ); // Effect-specific vars var wavesDirection = Math.max(0.0, Math.min(1.0, elm.getAttribute('data-image-effect-waves-direction') ) ); // Curtains init var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'ripple2Texture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } var displacement_url = elm.getAttribute('data-image-effect-displacement'); if ( displacement_url ) { var displacement_img = document.createElement("img"); // displacement_img.setAttribute('crossorigin', 'anonymous'); displacement_img.setAttribute('src', displacement_url); displacement_img.setAttribute('data-sampler', 'ripple2Displacement'); if ( displacement_img.getAttribute( 'decoding' ) == 'async' ) { displacement_img.setAttribute( 'decoding', 'sync' ); } displacement_img.classList.add('trx_addons_image_effects_ripple_displacement'); parent.appendChild(displacement_img); $document.on('action.after_add_content', function(e, cont) { cont.find( '.trx_addons_image_effects_ripple_displacement' ).remove(); }); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params() { var vs = ` #ifdef GL_ES precision mediump float; #endif // default mandatory variables attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrices // notice how it matches our data-sampler attributes + "Matrix" uniform mat4 ripple2TextureMatrix; // varying variables varying vec3 vVertexPosition; // our displacement texture will use original texture coords attributes varying vec2 vDisplacementCoord; // our image will use texture coords based on their texture matrices varying vec2 vTextureCoord; // custom uniforms uniform float uTime; void main() { vec3 vertexPosition = aVertexPosition; gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0); // varying variables // texture coords attributes because we want our displacement texture to be contained vDisplacementCoord = aTextureCoord; // our image texture coords based on their texture matrices vTextureCoord = (ripple2TextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; // vertex position as usual vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // all our varying variables varying vec3 vVertexPosition; varying vec2 vDisplacementCoord; varying vec2 vTextureCoord; // our textures samplers // notice how it matches our data-sampler attributes uniform sampler2D ripple2Texture; uniform sampler2D ripple2Displacement; // effect control vars declared inside our javascript uniform float uTime; // time iterator to change waves position uniform float uEffectStrength; // 5.0 - 50.0 - waves amplitude uniform float uWavesForce; // 0.0 - 1.0 - fadeIn/fadeOut on mouse hover uniform float uWavesDirection; // 0 - horizontal, 1 - vertical void main( void ) { // our displacement texture vec2 displacementCoords = vDisplacementCoord; displacementCoords = vec2( mod(displacementCoords.x - (1.0 - uWavesDirection) * uTime / ( 400.0 + uEffectStrength * 5.0 ), 1.0), mod(displacementCoords.y - uWavesDirection * uTime / ( 600.0 + uEffectStrength * 5.0 ), 1.0) ); vec4 displacementTexture = texture2D(ripple2Displacement, displacementCoords); // image texture vec2 textureCoords = vTextureCoord; // displace our pixels along both axis based on our time uniform and texture UVs // this will create a kind of water surface effect // try to comment a line or change the constants to see how it changes the effect // reminder : textures coords are ranging from 0.0 to 1.0 on both axis const float PI = 3.141592; textureCoords.x += 1.0 / uEffectStrength / ( 2.5 + 1.5 * uWavesDirection ) * uWavesForce * displacementTexture.r; textureCoords.y -= 1.0 / uEffectStrength / ( 2.0 + 1.5 * ( 1.0 - uWavesDirection ) ) * uWavesForce * displacementTexture.r; vec4 finalColor = texture2D(ripple2Texture, textureCoords); // handling premultiplied alpha and apply displacement finalColor = vec4(finalColor.rgb * finalColor.a, finalColor.a); // apply our shader gl_FragColor = finalColor; } `; return { vertexShader: vs, // our vertex shader ID fragmentShader: fs, // our fragment shader ID // widthSegments: 10, // heightSegments: 10, imageCover: false, // our displacement texture has to fit the plane uniforms: { // variables passed to shaders time: { name: "uTime", type: "1f", value: 0 }, effectStrength: { name: "uEffectStrength", type: "1f", value: effectStrength }, wavesForce: { name: "uWavesForce", type: "1f", value: 0 }, wavesDirection: { name: "uWavesDirection", type: "1f", value: wavesDirection } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { // console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenForce = null; plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_waves_force( 1 ); change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_waves_force( 0 ); change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { plane.uniforms.time.value++; }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); }); // Change wave force value function change_waves_force( to ) { if ( plane.tweenForce ) { trx_addons_tween_stop( plane.tweenForce ); } plane.tweenForce = trx_addons_tween_value( { start: plane.uniforms.wavesForce.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.wavesForce.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tweenForce ); plane.tweenForce = null; } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to === 0 ) { curtains.disableDrawing(); } } } } ); } } }; // Effect 'Smudge' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_smudge = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; var enableDrawing = false; // track the mouse positions to send it to the shaders var mousePosition = { x: 0, y: 0 }; // we will keep track of the last position in order to calculate the movement strength/delta var mouseLastPosition = { x: 0, y: 0 }; var mouseStrength = false; var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var paddingOnHover = typeof trx_addons_apply_filters == 'function' ? trx_addons_apply_filters( 'trx_addons_filter_image_effects_padding', 0.04, 'smudge' ) : 0.04; var effectStrength = Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30.0 ) ); var deltas = { max: 0, applied: 0 }; var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'smudgeTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params( elm, img, parent ) { var vs = ` #ifdef GL_ES precision mediump float; #endif // default mandatory variables attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrix uniform mat4 smudgeTextureMatrix; // custom variables varying vec3 vVertexPosition; varying vec2 vTextureCoord; uniform float uTime; //uniform vec2 uResolution; uniform vec2 uMousePosition; uniform float uMouseMoveStrength; uniform float uEffectStrength; uniform float uPadding; void main() { vec3 vertexPosition = aVertexPosition; // get the distance between our vertex and the mouse position float distanceFromMouse = distance(uMousePosition, vec2(vertexPosition.x, vertexPosition.y)); // attenuate the effect based on mouse distance float distanceStrength = 0.4 / (distanceFromMouse + 0.4); // calculate our distortion effect float distortionEffect = distanceStrength * uMouseMoveStrength / uEffectStrength; // apply it to our vertex position vertexPosition.z += distortionEffect; //vertexPosition.x += distortionEffect * (uMousePosition.x - vertexPosition.x) * (uResolution.x / uResolution.y); vertexPosition.x += distortionEffect * (uMousePosition.x - vertexPosition.x); vertexPosition.y += distortionEffect * (uMousePosition.y - vertexPosition.y); gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, (1.0 + uPadding)); // varyings vTextureCoord = (smudgeTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif varying vec3 vVertexPosition; varying vec2 vTextureCoord; uniform sampler2D smudgeTexture; void main() { // apply our texture vec4 finalColor = texture2D(smudgeTexture, vTextureCoord); // fake shadows based on vertex position along Z axis finalColor.rgb -= clamp(-vVertexPosition.z, 0.0, 1.0); // fake lights based on vertex position along Z axis finalColor.rgb += clamp(vVertexPosition.z, 0.0, 1.0); // handling premultiplied alpha (useful if we were using a png with transparency) finalColor = vec4(finalColor.rgb * finalColor.a, finalColor.a); gl_FragColor = finalColor; } `; return { vertexShader: vs, fragmentShader: fs, widthSegments: 20, heightSegments: 20, uniforms: { /* resolution: { // resolution of our plane name: "uResolution", type: "2f", // notice this is an length 2 array of floats value: [ parent.clientWidth, parent.clientHeight ] }, */ time: { // time uniform that will be updated at each draw call name: "uTime", type: "1f", value: 0 }, mousePosition: { // our mouse position name: "uMousePosition", type: "2f", // again an array of floats value: [ mousePosition.x, mousePosition.y ] }, mouseMoveStrength: { // the mouse move strength name: "uMouseMoveStrength", type: "1f", value: 0 }, effectStrength: { // the smudge strength name: "uEffectStrength", type: "1f", value: effectStrength }, padding: { // paddings around image on hover name: "uPadding", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { //console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // set a fov of 35 to reduce perspective plane.setPerspective(35); // apply a little effect once everything is ready deltas.max = 2; // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } handle_movement(e, plane); } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_scale( 1 ); if ( paddingOnHover ) { change_padding(paddingOnHover); } } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_scale( 0 ); if ( paddingOnHover ) { change_padding(0); } } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { // increment our time uniform plane.uniforms.time.value++; // decrease both deltas by damping : if the user doesn't move the mouse, effect will fade away deltas.applied += (deltas.max - deltas.applied) * 0.02; deltas.max += (0 - deltas.max) * 0.01; // send the new mouse move strength value plane.uniforms.mouseMoveStrength.value = deltas.applied; if ( ! permanentDrawing && ! enableDrawing && Math.abs(deltas.applied - deltas.max) < 0.001 ) { curtains.disableDrawing(); } }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); /* var planeBoundingRect = plane.getBoundingRect(); plane.uniforms.resolution.value = [planeBoundingRect.width, planeBoundingRect.height]; */ }); } // handle the mouse move event function handle_movement(e, plane) { // update mouse last pos mouseLastPosition.x = mousePosition.x; mouseLastPosition.y = mousePosition.y; var mouse = {}; // touch event if (e.targetTouches) { mouse.x = globalCanvas ? e.targetTouches[0].clientX : e.targetTouches[0].layerX; mouse.y = globalCanvas ? e.targetTouches[0].clientY : e.targetTouches[0].layerY; // mouse event } else { // In Chrome with custom scroll mouse coordinates in layerXY are incorrect // but in Mozilla mouse properties offsetXY always empty (equal to 0) mouse.x = globalCanvas ? e.clientX : ( e.offsetX !== 0 || e.offsetY !== 0 ? e.offsetX : e.layerX ); mouse.y = globalCanvas ? e.clientY : ( e.offsetX !== 0 || e.offsetY !== 0 ? e.offsetY : e.layerY ); } // lerp the mouse position a bit to smoothen the overall effect mousePosition.x = trx_addons_lerp(mousePosition.x, mouse.x, 0.3); mousePosition.y = trx_addons_lerp(mousePosition.y, mouse.y, 0.3); // convert our mouse/touch position to coordinates relative to the vertices of the plane var mouseCoords = globalCanvas ? plane.mouseToPlaneCoords(mousePosition.x, mousePosition.y) : mouse_to_plane_coords( plane, mousePosition ); // update our mouse position uniform plane.uniforms.mousePosition.value = [mouseCoords.x, mouseCoords.y]; // calculate the mouse move strength if ( mouseStrength && mouseLastPosition.x && mouseLastPosition.y ) { var delta = Math.sqrt( Math.pow( mousePosition.x - mouseLastPosition.x, 2 ) + Math.pow( mousePosition.y - mouseLastPosition.y, 2 ) ) / 20; delta = Math.min(4, delta); // update max delta only if it increased if ( delta >= deltas.max ) { deltas.max = delta; } } else { deltas.max = 2; } } // Change padding value function change_padding( to ) { if ( plane.tweenPadding ) { trx_addons_tween_stop( plane.tweenPadding ); } plane.tweenPadding = trx_addons_tween_value( { start: plane.uniforms.padding.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.padding.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tweenPadding ); plane.tweenPadding = null; } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { enableDrawing = true; curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to === 0 ) { enableDrawing = false; //curtains.disableDrawing(); } } } } ); } }; // Effect 'Tint' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_tint = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0, tintColor = elm.getAttribute('data-image-effect-tint-color') || TRX_ADDONS_STORAGE['theme_accent_color']; var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'tintTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params( elm, img, parent ) { var vs = ` #ifdef GL_ES precision mediump float; #endif vec3 permute(vec3 x) { return mod((x*34.0+1.0)*x, 289.0); } float snoise(vec2 v) { const vec4 C = vec4(0.211325, 0.366025, -0.57735, 0.02439); vec2 i = floor(v + dot(v, C.yy)), x0 = v - i + dot(i, C.xx), i1; i1 = x0.x > x0.y ? vec2(1.0, 0.0) : vec2(0.0,1.0); vec4 x12 = x0.xyxy + C.xxzz; x12.xy -= i1, i = mod(i, 289.0); vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0,i1.x, 1.0)), m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0); m = m * m, m = m * m; vec3 x = 2.0 * fract(p * C.www) - 1.0, h = abs(x) - 0.5, ox = floor(x + 0.5), a0 = x - ox; m *= 1.792843 - 0.853735 * (a0 * a0 + h * h); vec3 g; g.x = a0.x * x0.x + h.x * x0.y, g.yz = a0.yz * x12.xz + h.yz * x12.yw; return 130.0 * dot(m, g); } attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix, uPMatrix, tintTextureMatrix; uniform float uTime, uMouseOver; varying vec2 vTintTextureCoord; varying vec3 vVertexPosition, vNoise; void main(){ vec3 vP = aVertexPosition; vec2 sUV = vec2(vP.x * 0.75, vP.y * 0.75); vec3 sN = vec3(snoise(sUV * 2.0 - uTime / 360.0)); vP.z = 0.0, gl_Position = uPMatrix * uMVMatrix * vec4(vP, 1.0), vVertexPosition = vP, vTintTextureCoord = (tintTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy, vNoise = sN; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif varying vec2 vTintTextureCoord; varying vec3 vVertexPosition; varying vec3 vNoise; uniform sampler2D tintTexture; uniform float uMouseOver; uniform vec3 uColor; void main(){ vec4 f = texture2D(tintTexture, vTintTextureCoord); f.rgb -= clamp(-vVertexPosition.z / 10.0, 0.0, 1.0); f.rgb += clamp( vVertexPosition.z / 12.5, 0.0, 1.0); vec4 lC = vec4(0.299, 0.587, 0.114, 0.0), l = vec4(1.0), tint = vec4(uColor.r / 255.0, uColor.g / 255.0, uColor.b / 255.0, 1.0); float lM = dot(f, lC), mN = clamp(uMouseOver * (1.0 - vNoise.r) - 1.0 + uMouseOver * 2.0, 0.0, 1.0); vec4 mC = (l + tint) / vec4(2.0), dT = lM >= 0.45 ? mix(mC, l, smoothstep(0.45, 0.93125, lM)) : mix(tint, mC, smoothstep(-0.03125, 0.45, lM)); f = mix(dT, f, step(0.9, mN)); f = vec4(f.rgb * f.a, f.a); gl_FragColor = f; } `; return { vertexShader: vs, fragmentShader: fs, widthSegments: 5, heightSegments: 40, fov: 45, drawCheckMargins: { top: 15, right: 0, bottom: 15, left: 0 }, uniforms: { time: { name: "uTime", type: "1f", value: 0 // 180 * index }, mouseOver: { name: "uMouseOver", type: "1f", value: 0 }, color: { name: "uColor", type: "3f", value: trx_addons_rgb2components(tintColor) } } }; } // handle plane function handle_plane( plane ) { plane .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tween = null; plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_mouse_over( 1 ); change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_mouse_over( 0 ); change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { plane.uniforms.time.value++; }); } // Change wave force value function change_mouse_over( to ) { if ( plane.tween ) { trx_addons_tween_stop( plane.tween ); } plane.tween = trx_addons_tween_value( { start: plane.uniforms.mouseOver.value, end: to, time: 1.25, callbacks: { onUpdate: function(value) { plane.uniforms.mouseOver.value = value; }, onComplete: function() { trx_addons_tween_stop( plane.tween ); plane.tween = null } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to === 0 ) { curtains.disableDrawing(); } } } } ); } }; // Effect 'Swap' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_swap = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; // Common vars var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var activeImage = 0; // Curtains init var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'swapTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } var swap_url = elm.getAttribute('data-image-effect-swap-image'); if ( swap_url ) { var swap_img = document.createElement("img"); // swap_img.setAttribute('crossorigin', 'anonymous'); swap_img.setAttribute('src', swap_url); swap_img.setAttribute('data-sampler', 'swap2Texture'); if ( swap_img.getAttribute( 'decoding' ) == 'async' ) { swap_img.setAttribute( 'decoding', 'sync' ); } swap_img.classList.add('trx_addons_image_effects_swap_image'); parent.appendChild(swap_img); $document.on('action.after_add_content', function(e, cont) { cont.find( '.trx_addons_image_effects_swap_image' ).remove(); }); } var displacement_url = elm.getAttribute('data-image-effect-displacement'); if ( displacement_url ) { var displacement_img = document.createElement("img"); // displacement_img.setAttribute('crossorigin', 'anonymous'); displacement_img.setAttribute('src', displacement_url); displacement_img.setAttribute('data-sampler', 'swapDisplacement'); if ( displacement_img.getAttribute( 'decoding' ) == 'async' ) { displacement_img.setAttribute( 'decoding', 'sync' ); } displacement_img.classList.add('trx_addons_image_effects_swap_displacement'); parent.appendChild(displacement_img); $document.on('action.after_add_content', function(e, cont) { cont.find( '.trx_addons_image_effects_swap_displacement' ).remove(); }); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params() { var vs = ` #ifdef GL_ES precision mediump float; #endif // default mandatory variables attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrices // notice how it matches our data-sampler attributes + "Matrix" uniform mat4 swapTextureMatrix; uniform mat4 swap2TextureMatrix; // varying variables varying vec3 vVertexPosition; // our displacement texture will use original texture coords attributes varying vec2 vTextureCoord; // our image will use texture coords based on their texture matrices varying vec2 vSwapTextureCoord; varying vec2 vSwap2TextureCoord; // custom uniforms uniform float uTime; void main() { vec3 vertexPosition = aVertexPosition; gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0); // varying variables // texture coords attributes because we want our displacement texture to be contained vTextureCoord = aTextureCoord; // our image texture coords based on their texture matrices vSwapTextureCoord = (swapTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vSwap2TextureCoord = (swap2TextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; // vertex position as usual vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // all our varying variables varying vec3 vVertexPosition; varying vec2 vTextureCoord; varying vec2 vSwapTextureCoord; varying vec2 vSwap2TextureCoord; // custom uniforms uniform float uTime; // our textures samplers // notice how it matches our data-sampler attributes uniform sampler2D swapTexture; uniform sampler2D swap2Texture; uniform sampler2D swapDisplacement; void main( void ) { // our texture coords vec2 textureCoords = vTextureCoord; // our displacement texture vec4 displacementTexture = texture2D(swapDisplacement, textureCoords); // our displacement factor is a float varying from 1 to 0 based on the timer float displacementFactor = 1.0 - (cos(uTime / (60.0 / 3.141592)) + 1.0) / 2.0; // the effect factor will tell which way we want to displace our pixels // the farther from the center of the videos, the stronger it will be vec2 effectFactor = vec2((textureCoords.x - 0.5) * 0.75, (textureCoords.y - 0.5) * 0.75); // calculate our displaced coordinates of the first video vec2 firstDisplacementCoords = vec2(vSwapTextureCoord.x - displacementFactor * (displacementTexture.r * effectFactor.x), vSwapTextureCoord.y- displacementFactor * (displacementTexture.r * effectFactor.y)); // opposite displacement effect on the second video vec2 secondDisplacementCoords = vec2(vSwap2TextureCoord.x - (1.0 - displacementFactor) * (displacementTexture.r * effectFactor.x), vSwap2TextureCoord.y - (1.0 - displacementFactor) * (displacementTexture.r * effectFactor.y)); // apply the textures vec4 firstDistortedColor = texture2D(swapTexture, firstDisplacementCoords); vec4 secondDistortedColor = texture2D(swap2Texture, secondDisplacementCoords); // blend both textures based on our displacement factor vec4 finalColor = mix(firstDistortedColor, secondDistortedColor, displacementFactor); // handling premultiplied alpha finalColor = vec4(finalColor.rgb * finalColor.a, finalColor.a); // apply our shader gl_FragColor = finalColor; } `; return { vertexShader: vs, // our vertex shader ID fragmentShader: fs, // our fragment shader ID // widthSegments: 10, // heightSegments: 10, imageCover: false, // our displacement texture has to fit the plane uniforms: { // variables passed to shaders time: { name: "uTime", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { // console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; activeImage = 1; change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; activeImage = 0; change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { plane.uniforms.time.value = activeImage == 1 ? Math.min(60, plane.uniforms.time.value + 1) : Math.max(0, plane.uniforms.time.value - 1); }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); }); // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing ) { curtains.disableDrawing(); } } } } ); } } }; // Effect 'Fish' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_fish = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; // Common vars var mouseIn = false; // track the mouse positions to send it to the shaders var mousePosition = { x: 0, y: 0 }; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var activeImage = 0; // Curtains init var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'swapTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } var swap_url = elm.getAttribute('data-image-effect-swap-image'); if ( swap_url ) { var swap_img = document.createElement("img"); // swap_img.setAttribute('crossorigin', 'anonymous'); swap_img.setAttribute('src', swap_url); swap_img.setAttribute('data-sampler', 'swap2Texture'); if ( swap_img.getAttribute( 'decoding' ) == 'async' ) { swap_img.setAttribute( 'decoding', 'sync' ); } swap_img.classList.add('trx_addons_image_effects_swap_image'); parent.appendChild(swap_img); $document.on('action.after_add_content', function(e, cont) { cont.find( '.trx_addons_image_effects_swap_image' ).remove(); }); } var displacement_url = elm.getAttribute('data-image-effect-displacement'); if ( displacement_url ) { var displacement_img = document.createElement("img"); // displacement_img.setAttribute('crossorigin', 'anonymous'); displacement_img.setAttribute('src', displacement_url); displacement_img.setAttribute('data-sampler', 'swapDisplacement'); if ( displacement_img.getAttribute( 'decoding' ) == 'async' ) { displacement_img.setAttribute( 'decoding', 'sync' ); } displacement_img.classList.add('trx_addons_image_effects_swap_displacement'); parent.appendChild(displacement_img); $document.on('action.after_add_content', function(e, cont) { cont.find( '.trx_addons_image_effects_swap_displacement' ).remove(); }); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params() { var vs = ` #ifdef GL_ES precision mediump float; #endif // default mandatory variables attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; // our texture matrices // notice how it matches our data-sampler attributes + "Matrix" uniform mat4 swapTextureMatrix; uniform mat4 swap2TextureMatrix; // varying variables varying vec3 vVertexPosition; // our displacement texture will use original texture coords attributes varying vec2 vTextureCoord; // our image will use texture coords based on their texture matrices varying vec2 vSwapTextureCoord; varying vec2 vSwap2TextureCoord; // custom uniforms uniform float uTime; void main() { vec3 vertexPosition = aVertexPosition; gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0); // varying variables // texture coords attributes because we want our displacement texture to be contained vTextureCoord = aTextureCoord; // our image texture coords based on their texture matrices vSwapTextureCoord = (swapTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vSwap2TextureCoord = (swap2TextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; // vertex position as usual vVertexPosition = vertexPosition; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // all our varying variables varying vec3 vVertexPosition; varying vec2 vTextureCoord; varying vec2 vSwapTextureCoord; varying vec2 vSwap2TextureCoord; // custom uniforms uniform float uPR; uniform float uScale; uniform float uEffect; uniform float uTime; uniform vec2 uRes; uniform vec2 uMousePosition; // our textures samplers // notice how it matches our data-sampler attributes uniform sampler2D swapTexture; uniform sampler2D swap2Texture; uniform sampler2D swapDisplacement; float circle( in vec2 _st, in float _radius, in float blurriness ) { vec2 dist = _st; return 1. - smoothstep( _radius - ( _radius * blurriness ), _radius + ( _radius * blurriness ), dot( dist, dist ) * 4.0 ); } void main( void ) { // our texture coords vec2 textureCoords = vTextureCoord; //vec2 st = textureCoords - vec2(0.5); // Manage the device ratio vec2 res = uRes * uPR; vec2 st = gl_FragCoord.xy / res.xy - vec2(0.5); // tip: use the following formula to keep the good ratio of your coordinates st.y *= uRes.y / uRes.x; vec2 mouse = uMousePosition * -0.5; // tip2: do the same for your mouse mouse.y *= uRes.y / uRes.x; //mouse *= -1.; vec2 circlePos = st + mouse; float c = circle( circlePos, 0.3 * uScale, 2. ); // our displacement texture vec4 displacementTexture = texture2D(swapDisplacement, textureCoords); // our displacement factor is a float varying from 1 to 0 based on the timer float displacementFactor = ( 1.0 - (cos(uTime / (60.0 / 3.141592)) + 1.0) / 2.0 * uEffect ) * c; // the effect factor will tell which way we want to displace our pixels // the farther from the center of the videos, the stronger it will be vec2 effectFactor = vec2( (textureCoords.x - 0.5) * 0.75 * uEffect, (textureCoords.y - 0.5) * 0.75 * uEffect ); // calculate our displaced coordinates of the first video vec2 firstDisplacementCoords = vec2(vSwapTextureCoord.x - displacementFactor * (displacementTexture.r * effectFactor.x), vSwapTextureCoord.y - displacementFactor * (displacementTexture.r * effectFactor.y)); // opposite displacement effect on the second video vec2 secondDisplacementCoords = vec2(vSwap2TextureCoord.x - (1.0 - displacementFactor) * (displacementTexture.r * effectFactor.x), vSwap2TextureCoord.y - (1.0 - displacementFactor) * (displacementTexture.r * effectFactor.y)); // apply the textures vec4 firstDistortedColor = texture2D(swapTexture, firstDisplacementCoords); vec4 secondDistortedColor = texture2D(swap2Texture, secondDisplacementCoords); // blend both textures based on our displacement factor vec4 finalColor = mix(firstDistortedColor, secondDistortedColor, displacementFactor); // handling premultiplied alpha finalColor = vec4(finalColor.rgb * finalColor.a, finalColor.a); // apply our shader gl_FragColor = finalColor; } `; return { vertexShader: vs, // our vertex shader ID fragmentShader: fs, // our fragment shader ID // widthSegments: 10, // heightSegments: 10, imageCover: false, // our displacement texture has to fit the plane uniforms: { // variables passed to shaders mousePosition: { // our mouse position name: "uMousePosition", type: "2f", value: [ mousePosition.x, mousePosition.y ] }, imageResolution: { name: "uRes", type: "2f", value: [ img.clientWidth, img.clientHeight ] }, pixelRatio: { name: "uPR", type: "1f", value: window.devicePixelRatio.toFixed(1) }, scaleFactor: { name: "uScale", type: "1f", value: 0 }, useEffect: { name: "uEffect", type: "1f", value: displacement_url != '' ? 1 : 0 }, time: { name: "uTime", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { // console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } handle_movement(e, plane); } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; activeImage = 1; change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; activeImage = 0; change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { plane.uniforms.time.value = activeImage == 1 ? Math.min(60, plane.uniforms.time.value + 1) : Math.max(0, plane.uniforms.time.value - 1); }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); }); // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing && to == 1 ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.25, callbacks: { onUpdate: function(value) { scaleFactor = value; plane.uniforms.scaleFactor.value = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to == 0 ) { curtains.disableDrawing(); } } } } ); } } // handle the mouse move event function handle_movement(e, plane) { var mouse = get_mouse_position_from_event( e ); // lerp the mouse position a bit to smoothen the overall effect mousePosition.x = trx_addons_lerp(mousePosition.x, mouse.x, 0.3); mousePosition.y = trx_addons_lerp(mousePosition.y, mouse.y, 0.3); // convert our mouse/touch position to coordinates relative to the vertices of the plane var mouseCoords = globalCanvas ? plane.mouseToPlaneCoords(mousePosition.x, mousePosition.y) : mouse_to_plane_coords( plane, mousePosition ); // update our mouse position uniform plane.uniforms.mousePosition.value = [mouseCoords.x, mouseCoords.y]; } }; // Effect 'Blot' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_blot = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; // Common vars var mouseIn = false; // track the mouse positions to send it to the shaders var mousePosition = { x: 0, y: 0 }; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0, tintColor = elm.getAttribute('data-image-effect-tint-color') || ''; var effectStrength = Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30.0 ) ); var wavesDirection = Math.max(0.0, Math.min(1.0, elm.getAttribute('data-image-effect-waves-direction') ) ); var activeImage = 0; // Curtains init var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'swapTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } var swap_url = elm.getAttribute('data-image-effect-swap-image'); if ( swap_url ) { var swap_img = document.createElement("img"); // swap_img.setAttribute('crossorigin', 'anonymous'); swap_img.setAttribute('src', swap_url); swap_img.setAttribute('data-sampler', 'swap2Texture'); if ( swap_img.getAttribute( 'decoding' ) == 'async' ) { swap_img.setAttribute( 'decoding', 'sync' ); } swap_img.classList.add('trx_addons_image_effects_swap_image'); parent.appendChild(swap_img); $document.on('action.after_add_content', function(e, cont) { cont.find( '.trx_addons_image_effects_swap_image' ).remove(); }); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { if ( ! permanentDrawing ) curtains.disableDrawing(); plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params() { var vs = ` #ifdef GL_ES precision mediump float; #endif // default mandatory variables attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uPMatrix; uniform mat4 uMVMatrix; // our texture matrices // notice how it matches our data-sampler attributes + "Matrix" uniform mat4 swapTextureMatrix; uniform mat4 swap2TextureMatrix; // our displacement texture will use original texture coords attributes varying vec2 vTextureCoord; // our image will use texture coords based on their texture matrices varying vec2 vSwapTextureCoord; varying vec2 vSwap2TextureCoord; void main() { // texture coords attributes because we want our displacement texture to be contained // our image texture coords based on their texture matrices vTextureCoord = aTextureCoord; vSwapTextureCoord = (swapTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; vSwap2TextureCoord = (swap2TextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy; gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // all our varying variables //varying vec3 vVertexPosition; varying vec2 vTextureCoord; varying vec2 vSwapTextureCoord; varying vec2 vSwap2TextureCoord; // custom uniforms uniform float uPR; uniform float uScale; uniform float uTint; uniform float uWavesTime; uniform float uTime; uniform vec2 uRes; uniform vec2 uMousePosition; uniform vec3 uColor; // our textures samplers // notice how it matches our data-sampler attributes uniform sampler2D swapTexture; uniform sampler2D swap2Texture; uniform float uEffectStrength; // 5.0 - 50.0 - waves amplitude uniform float uWavesDirection; // 0 - horizontal, 1 - vertical // noise 2d generator //--------------------------------------------------- vec3 permute3(vec3 x) { return mod((x*34.0+1.0)*x, 289.0); } float snoise2(vec2 v) { const vec4 C = vec4(0.211325, 0.366025, -0.57735, 0.02439); vec2 i = floor(v + dot(v, C.yy)), x0 = v - i + dot(i, C.xx), i1; i1 = x0.x > x0.y ? vec2(1.0, 0.0) : vec2(0.0,1.0); vec4 x12 = x0.xyxy + C.xxzz; x12.xy -= i1, i = mod(i, 289.0); vec3 p = permute3(permute3(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0,i1.x, 1.0)), m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0); m = m * m, m = m * m; vec3 x = 2.0 * fract(p * C.www) - 1.0, h = abs(x) - 0.5, ox = floor(x + 0.5), a0 = x - ox; m *= 1.792843 - 0.853735 * (a0 * a0 + h * h); vec3 g; g.x = a0.x * x0.x + h.x * x0.y, g.yz = a0.yz * x12.xz + h.yz * x12.yw; return 130.0 * dot(m, g); } // noise 3d generator //------------------------------------------- vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute4(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } float snoise3(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); // First corner vec3 i = floor(v + dot(v, C.yyy) ); vec3 x0 = v - i + dot(i, C.xxx) ; // Other corners vec3 g = step(x0.yzx, x0.xyz); vec3 l = 1.0 - g; vec3 i1 = min( g.xyz, l.zxy ); vec3 i2 = max( g.xyz, l.zxy ); // x0 = x0 - 0.0 + 0.0 * C.xxx; // x1 = x0 - i1 + 1.0 * C.xxx; // x2 = x0 - i2 + 2.0 * C.xxx; // x3 = x0 - 1.0 + 3.0 * C.xxx; vec3 x1 = x0 - i1 + C.xxx; vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations i = mod289(i); vec4 p = permute4( permute4( permute4( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) float n_ = 0.142857142857; // 1.0/7.0 vec3 ns = n_ * D.wyz - D.xzx; vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) vec4 x_ = floor(j * ns.z); vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) vec4 x = x_ *ns.x + ns.yyyy; vec4 y = y_ *ns.x + ns.yyyy; vec4 h = 1.0 - abs(x) - abs(y); vec4 b0 = vec4( x.xy, y.xy ); vec4 b1 = vec4( x.zw, y.zw ); //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; vec4 s0 = floor(b0)*2.0 + 1.0; vec4 s1 = floor(b1)*2.0 + 1.0; vec4 sh = -step(h, vec4(0.0)); vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; vec3 p0 = vec3(a0.xy,h.x); vec3 p1 = vec3(a0.zw,h.y); vec3 p2 = vec3(a1.xy,h.z); vec3 p3 = vec3(a1.zw,h.w); //Normalise gradients vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w; // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } // circle //------------------------------------------- float circle( in vec2 _st, in float _radius, in float blurriness ) { vec2 dist = _st; return 1. - smoothstep( _radius - ( _radius * blurriness ), _radius + ( _radius * blurriness ), dot( dist, dist ) * 4.0 ); } void main( void ) { vec2 v_uv = vTextureCoord; vec2 v_sv = vSwapTextureCoord; // Manage the device ratio vec2 res = uRes * uPR; vec2 st = gl_FragCoord.xy / res.xy - vec2(0.5); // tip: use the following formula to keep the good ratio of your coordinates st.y *= uRes.y / uRes.x; vec2 mouse = uMousePosition * -0.5; // tip2: do the same for your mouse mouse.y *= uRes.y / uRes.x; //mouse *= -1.; vec2 circlePos = st + mouse; // float c = circle( circlePos, 0.3 * uScale, 2.0 ) * 2.5; float c = circle( circlePos, 0.3 * uScale, 2.5 ) * 2.25; float offx = v_uv.x + sin( v_uv.y + uTime * 0.1 ); float offy = v_uv.y - uTime * 0.1 - cos( uTime * 0.001 ) * 0.01; float n = snoise3( vec3( offx, offy, uTime * 0.1 ) * 8.0 ) - 1.0; float finalMask = smoothstep( 0.4, 0.5, n + pow( c, 2.0 ) ); // Add waves to the first image const float PI = 3.141592; v_sv.x += ( sin(v_sv.x * 10.0 * ( 2.0 - uWavesDirection ) + ((uWavesTime * (PI / 3.0)) * 0.031)) + sin(v_sv.y * 10.0 * ( 2.0 - uWavesDirection ) + ((uWavesTime * (PI / 2.489)) * 0.017)) ) / uEffectStrength / ( 2.5 + 1.5 * uWavesDirection ) * uScale; // * 0.0075; v_sv.y += ( sin(v_sv.y * 20.0 / ( 2.0 - uWavesDirection ) + ((uWavesTime * (PI / 2.023)) * 0.023)) + sin(v_sv.x * 20.0 / ( 2.0 - uWavesDirection ) + ((uWavesTime * (PI / 3.1254)) * 0.037)) ) / uEffectStrength / ( 2.5 + 1.5 * ( 1.0 - uWavesDirection ) ) * uScale; // * 0.0125; vec4 imageColor = texture2D( swapTexture, v_sv ); // Add tint the second image vec4 hoverColor = texture2D( swap2Texture, vSwap2TextureCoord ); vec4 tint = vec4( uColor.r / 255.0, uColor.g / 255.0, uColor.b / 255.0, 1.0 ); hoverColor = uTint > 0.0 ? mix( hoverColor, tint, 0.5) : hoverColor; gl_FragColor = mix( imageColor, hoverColor, finalMask ); } `; return { vertexShader: vs, // our vertex shader ID fragmentShader: fs, // our fragment shader ID // widthSegments: 10, // heightSegments: 10, imageCover: false, // our displacement texture has to fit the plane uniforms: { // variables passed to shaders mousePosition: { // our mouse position name: "uMousePosition", type: "2f", value: [ mousePosition.x, mousePosition.y ] }, imageResolution: { name: "uRes", type: "2f", value: [ img.clientWidth, img.clientHeight ] }, pixelRatio: { name: "uPR", type: "1f", value: window.devicePixelRatio.toFixed(1) }, scaleFactor: { name: "uScale", type: "1f", value: 0 }, color: { name: "uColor", type: "3f", value: tintColor ? trx_addons_rgb2components( tintColor ) : [0, 0, 0] }, useColor: { name: "uTint", type: "1f", value: tintColor ? 1 : 0 }, effectStrength: { name: "uEffectStrength", type: "1f", value: effectStrength }, wavesDirection: { name: "uWavesDirection", type: "1f", value: wavesDirection }, wavesTime: { name: "uWavesTime", type: "1f", value: 0 }, time: { name: "uTime", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onLoading(function() { // console.log(plane.loadingManager.sourcesLoaded); }) .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // first render plane if ( ! permanentDrawing ) curtains.needRender(); // init tweens plane.tweenScale = null; // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } handle_movement(e, plane); } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; activeImage = 1; change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; activeImage = 0; change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { plane.uniforms.time.value += 0.01; plane.uniforms.wavesTime.value++; }) .onAfterResize(function() { // console.log('Plane '+index+' of '+total+' is resized'); }); // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing && to == 1 ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 0.6, callbacks: { onUpdate: function(value) { scaleFactor = value; plane.uniforms.scaleFactor.value = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; if ( ! permanentDrawing && to == 0 ) { curtains.disableDrawing(); } } } } ); } } // handle the mouse move event function handle_movement(e, plane) { var mouse = get_mouse_position_from_event( e ); // lerp the mouse position a bit to smoothen the overall effect mousePosition.x = trx_addons_lerp(mousePosition.x, mouse.x, 0.3); mousePosition.y = trx_addons_lerp(mousePosition.y, mouse.y, 0.3); // convert our mouse/touch position to coordinates relative to the vertices of the plane var mouseCoords = globalCanvas ? plane.mouseToPlaneCoords(mousePosition.x, mousePosition.y) : mouse_to_plane_coords( plane, mousePosition ); // update our mouse position uniform plane.uniforms.mousePosition.value = [mouseCoords.x, mouseCoords.y]; } }; // Effect 'Scroller' //------------------------------------------- // Create plane. // Attention! All callbacks must be in a global scope! window.trx_addons_image_effects_callback_scroller = function( curtains_global, elm, index, total ) { var curtains = curtains_global ? curtains_global : null; var mouseIn = false; var scaleOnHover = elm.getAttribute('data-image-effect-scale') > 0, scaleFactor = 0; var scrollDirection = 0, scrollY = -1; var effectStrength = 60 - Math.max( 5.0, Math.min( 50.0, elm.getAttribute('data-image-effect-strength') || 30 ) ), effectDirection = elm.getAttribute('data-image-effect-waves-direction') || 0; var plane = null, parent = null, img_all = elm.querySelectorAll( 'img:not([class*="trx_addons_image_effects_"])' ), img = img_all.length > 1 ? elm.querySelector( 'img:not([class*="avatar"]):not([class*="trx_addons_extended_taxonomy_img"])' ) : elm.querySelector( 'img' ); if ( img ) { if ( img_all.length > 1 ) { jQuery( img ).wrap( '<div class="trx_addons_image_effects_holder"></div>' ); } parent = img.parentNode; if ( img_all.length == 1 ) { parent.classList.add('trx_addons_image_effects_holder'); } // img.setAttribute('crossorigin', 'anonymous'); img.setAttribute('data-sampler', 'scrollerTexture'); if ( img.getAttribute( 'decoding' ) == 'async' ) { img.setAttribute( 'decoding', 'sync' ); } if ( ! globalCanvas ) { curtains = create_canvas(parent); if ( curtains ) jQuery(elm).data('curtains', curtains); } if ( curtains ) { plane = curtains.addPlane( parent, get_params( elm, img, parent ) ); if ( plane ) { jQuery(elm).data('curtains-plane', plane); handle_plane( plane ); } } } // Return plane params function get_params( elm, img, parent ) { var vs = ` #ifdef GL_ES precision mediump float; #endif attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; uniform mat4 uMVMatrix, uPMatrix; uniform float uScrollSpeed; uniform float uEffectStrength; uniform float uEffectDirection; uniform float uPadding; // our texture matrices // notice how it matches our data-sampler attributes + "Matrix" uniform mat4 scrollerTextureMatrix; // if you want to pass your vertex and texture coords to the fragment shader varying vec3 vVertexPosition; varying vec2 vScrollerTextureCoord; void main(){ vec3 vertexPosition = aVertexPosition; if ( uEffectDirection > 0.0 ) { // Vertical wave vertexPosition.x += sin( ( vertexPosition.y + 1.0 ) * 3.141592 ) * sin( uScrollSpeed * 3.141592 ) * 0.05 * ( uEffectStrength / 30.0 ); } else { // Horizontal wave vertexPosition.y += sin( ( vertexPosition.x + 1.0 ) / 2.0 * 3.141592 ) * sin( uScrollSpeed * 3.141592 ) * 0.05 * ( uEffectStrength / 30.0 ); } vVertexPosition = vertexPosition; gl_Position = uPMatrix * uMVMatrix * vec4( vertexPosition, 1.0 + uPadding * ( uEffectStrength / 30.0 ) ); vScrollerTextureCoord = ( scrollerTextureMatrix * vec4( aTextureCoord, 0.0, 1.0 ) ).xy; } `; var fs = ` #ifdef GL_ES precision mediump float; #endif // all our varying variables varying vec2 vScrollerTextureCoord; uniform sampler2D scrollerTexture; void main(){ vec2 textureCoord = vScrollerTextureCoord; gl_FragColor = texture2D(scrollerTexture, textureCoord); } `; return { vertexShader: vs, fragmentShader: fs, widthSegments: 10, heightSegments: 10, uniforms: { padding: { name: "uPadding", type: "1f", value: trx_addons_apply_filters( 'trx_addons_filter_image_effects_padding', 0.05, 'scroller' ) }, effectStrength: { name: "uEffectStrength", type: "1f", value: effectStrength }, effectDirection: { name: "uEffectDirection", type: "1f", value: effectDirection }, scrollSpeed: { name: "uScrollSpeed", type: "1f", value: 0 } } }; } // handle plane function handle_plane( plane ) { plane .onReady(function() { // console.log('Plane '+index+' of '+total+' is ready'); // init tweens plane.tween = null; plane.tweenScale = null; var scrollBusy = false, clear_scroll_busy = trx_addons_throttle( function() { scrollBusy = false; }, 300, true ); function scroll_get() { return ( typeof window.scrollY != 'undefined' ? window.scrollY : window.pageYOffset ) || 0; } // now that our plane is ready we can listen to mouse move event function scroll_start(e) { clear_scroll_busy(); if ( scrollY < 0 ) { scrollY = scroll_get(); } else if ( ! scrollDirection ) { var scrollNew = scroll_get(); scrollDirection = scrollNew > scrollY ? 1 : -1; scrollBusy = true; change_scroll( 1 ); } } window.addEventListener("scroll", scroll_start ); // now that our plane is ready we can listen to mouse move event function mouse_move(e) { if ( ! mouseIn ) { mouse_enter(); } } function mouse_enter() { if ( ! mouseIn ) { mouseIn = true; change_scale( 1 ); } } function mouse_leave() { if ( mouseIn ) { mouseIn = false; change_scale( 0 ); } } elm.addEventListener("mousemove", mouse_move ); elm.addEventListener("touchmove", mouse_move ); elm.addEventListener("mouseenter", mouse_enter ); elm.addEventListener("touchstart", mouse_enter ); elm.addEventListener("mouseleave", mouse_leave ); elm.addEventListener("touchend", mouse_leave ); }) .onRender(function() { //plane.uniforms.time.value++; }); } // Change wave force value function change_scroll( to ) { if ( plane.tween ) { trx_addons_tween_stop( plane.tween ); } plane.tween = trx_addons_tween_value( { start: plane.uniforms.scrollSpeed.value, end: to, time: 1.5, callbacks: { onUpdate: function(value) { plane.uniforms.scrollSpeed.value = value * scrollDirection; }, onComplete: function() { scrollDirection = 0; scrollY = -1; plane.uniforms.scrollSpeed.value = 0; trx_addons_tween_stop( plane.tween ); plane.tween = null; } } } ); } // Change scale function change_scale( to ) { if ( plane.tweenScale ) { trx_addons_tween_stop( plane.tweenScale ); } if ( ! permanentDrawing && to == 1 ) { curtains.enableDrawing(); } plane.tweenScale = trx_addons_tween_value( { start: scaleFactor, end: to, time: 1.0, callbacks: { onUpdate: function(value) { scaleFactor = value; if ( scaleOnHover ) { plane.textures && plane.textures[0].setScale(1 + value / 12, 1 + value / 12); } }, onComplete: function() { trx_addons_tween_stop( plane.tweenScale ); plane.tweenScale = null; } } } ); } }; })();