diff --git a/blocks/waves/src/edit.js b/blocks/waves/src/edit.js
index 6152b07a..823da0c3 100644
--- a/blocks/waves/src/edit.js
+++ b/blocks/waves/src/edit.js
@@ -23,6 +23,8 @@ import { useDispatch, useSelect } from '@wordpress/data';
import { useState, useEffect, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
+const { run, parseColor, renderPreview } = window.a8cColorEffects;
+
const DEFAULT_COLORS = {
color1: '#000',
color2: '#555',
@@ -129,12 +131,15 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
DEFAULT_COLORS.color4,
};
- const renderPreview = ( newAttributes = {} ) =>
- window.a8cColorEffects.renderPreview( {
+ const updatePreview = ( newAttributes = {} ) =>
+ renderPreview( {
complexity: attributes.complexity,
mouseSpeed: 1,
fluidSpeed: 1,
- ...colors,
+ color1: parseColor( colors.color1 ),
+ color2: parseColor( colors.color2 ),
+ color3: parseColor( colors.color3 ),
+ color4: parseColor( colors.color4 ),
...newAttributes,
} );
@@ -149,7 +154,7 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
// Save the initial preview in the attributes
if ( attributes.previewImage === undefined ) {
- const previewImage = renderPreview();
+ const previewImage = updatePreview();
setAttributes( { previewImage } );
}
}, [] );
@@ -162,10 +167,39 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
backgroundImage: `url( "${ attributes.previewImage }" )`,
};
+ // To avoid recompiling shaders every frame uniform variables need to be
+ // mutable so a new reference doesn't have to be passed to run.
+ const dataset = useRef( {
+ complexity: attributes.complexity,
+ mouseSpeed: attributes.mouseSpeed,
+ fluidSpeed: attributes.fluidSpeed,
+ color1: parseColor( colors.color1 ),
+ color2: parseColor( colors.color2 ),
+ color3: parseColor( colors.color3 ),
+ color4: parseColor( colors.color4 ),
+ } );
+ useEffect( () => {
+ dataset.current.complexity = attributes.complexity;
+ dataset.current.mouseSpeed = attributes.mouseSpeed;
+ dataset.current.fluidSpeed = attributes.fluidSpeed;
+ dataset.current.color1 = parseColor( colors.color1 );
+ dataset.current.color2 = parseColor( colors.color2 );
+ dataset.current.color3 = parseColor( colors.color3 );
+ dataset.current.color4 = parseColor( colors.color4 );
+ }, [
+ attributes.complexity,
+ attributes.mouseSpeed,
+ attributes.fluidSpeed,
+ colors.color1,
+ colors.color2,
+ colors.color3,
+ colors.color4,
+ ] );
+
const canvasRef = useRef();
useEffect( () => {
- return window.a8cColorEffects.run( canvasRef.current );
- }, [ canvasRef.current ] );
+ return run( canvasRef.current, dataset.current );
+ }, [ canvasRef.current, dataset.current ] );
return (
<>
@@ -175,7 +209,7 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
label={ __( 'Complexity', 'waves' ) }
value={ attributes.complexity }
onChange={ ( complexity ) => {
- const previewImage = renderPreview( {
+ const previewImage = updatePreview( {
complexity,
} );
setAttributes( { complexity, previewImage } );
@@ -209,9 +243,9 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
{
label: __( 'Color 1', 'waves' ),
value: colors.color1,
- onChange: ( color1 ) => {
- const previewImage = renderPreview( {
- color1,
+ onChange: ( color1 = colors.color1 ) => {
+ const previewImage = updatePreview( {
+ color1: parseColor( color1 ),
} );
setAttributes( { color1, previewImage } );
},
@@ -219,9 +253,9 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
{
label: __( 'Color 2', 'waves' ),
value: colors.color2,
- onChange: ( color2 ) => {
- const previewImage = renderPreview( {
- color2,
+ onChange: ( color2 = colors.color2 ) => {
+ const previewImage = updatePreview( {
+ color2: parseColor( color2 ),
} );
setAttributes( { color2, previewImage } );
},
@@ -229,9 +263,9 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
{
label: __( 'Color 3', 'waves' ),
value: colors.color3,
- onChange: ( color3 ) => {
- const previewImage = renderPreview( {
- color3,
+ onChange: ( color3 = colors.color3 ) => {
+ const previewImage = updatePreview( {
+ color3: parseColor( color3 ),
} );
setAttributes( { color3, previewImage } );
},
@@ -239,9 +273,9 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
{
label: __( 'Color 4', 'waves' ),
value: colors.color4,
- onChange: ( color4 ) => {
- const previewImage = renderPreview( {
- color4,
+ onChange: ( color4 = colors.color4 ) => {
+ const previewImage = updatePreview( {
+ color4: parseColor( color4 ),
} );
setAttributes( { color4, previewImage } );
},
@@ -289,16 +323,7 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
showHandle={ isSelected }
>
-
+
{
document
.querySelectorAll( '.wp-block-a8c-waves canvas' )
- .forEach( a8cColorEffects.run );
+ .forEach( ( canvas ) => {
+ const dataset = {
+ color1: parseColor( canvas.dataset.color1 ),
+ color2: parseColor( canvas.dataset.color2 ),
+ color3: parseColor( canvas.dataset.color3 ),
+ color4: parseColor( canvas.dataset.color4 ),
+ complexity: Number.parseInt(
+ canvas.dataset.complexity,
+ 10
+ ),
+ mouseSpeed: Number.parseFloat(
+ canvas.dataset.mouseSpeed
+ ),
+ fluidSpeed: Number.parseFloat(
+ canvas.dataset.fluidSpeed
+ ),
+ };
+ run( canvas, dataset );
+ } );
} );
}
} )( ( twgl ) => {
@@ -115,7 +134,7 @@
function inverse( [ x1, x2 ], [ y1, y2 ] ) {
const a = ( x1 * x2 * ( -y1 + y2 ) ) / ( x1 - x2 );
const b = ( x1 * y1 - x2 * y2 ) / ( x1 - x2 );
- return function( x ) {
+ return function ( x ) {
return a / x + b;
};
}
@@ -157,30 +176,6 @@
textureInfo: twgl.createFramebufferInfo( gl, null, 512, 512 ),
} );
- /**
- * Convert a hex color string to a WebGL color vector.
- *
- * @param {string} color Hex color string (#FFFFFF or #FFF)
- * @return {number[]} RGB array for WebGL
- */
- function parseColor( color ) {
- let r = '0';
- let g = '0';
- let b = '0';
-
- if ( color.length === 7 ) {
- r = '0x' + color[ 1 ] + color[ 2 ];
- g = '0x' + color[ 3 ] + color[ 4 ];
- b = '0x' + color[ 5 ] + color[ 6 ];
- } else if ( color.length === 4 ) {
- r = '0x' + color[ 1 ] + color[ 1 ];
- g = '0x' + color[ 2 ] + color[ 2 ];
- b = '0x' + color[ 3 ] + color[ 3 ];
- }
-
- return [ r / 0xff, g / 0xff, b / 0xff ];
- }
-
/**
* Draw an individual block.
*
@@ -193,12 +188,29 @@
renderLiquidEffect( gl, state, program );
}
+ /**
+ * The parsed dataset from the canvas.
+ *
+ * @typedef {Object} Dataset
+ * @property {number[]} color1 First color of the gradient.
+ * @property {number[]} color2 Second color of the gradient.
+ * @property {number[]} color3 Third color of the gradient.
+ * @property {number[]} color4 Fourth color of the gradient.
+ * @property {number} complexity Integer complexity of the animation.
+ * @property {number} mouseSpeed Float mouse speed of the animation.
+ * @property {number} fluidSpeed Float fluid speed of the animation.
+ */
+
/**
* Draw the custom gradient to the framebuffer.
*
* @param {WebGLRenderingContext} gl WebGL rendering context
- * @param {Object} state Data state for the rendering frame
- * @param {Object} program Collection of program info and buffers
+ * @param {Object} state State for the rendering frame.
+ * @param {Dataset} state.dataset Dataset to use for rendering.
+ * @param {Object} program Collection of program info and buffers.
+ * @param {Object} program.programInfoGradient Gradient program info.
+ * @param {Object} program.screenBufferInfo Screen buffer info.
+ * @param {Object} program.textureInfo Texture info.
*/
function renderGradient(
gl,
@@ -206,10 +218,10 @@
{ programInfoGradient, screenBufferInfo, textureInfo }
) {
const uniforms = {
- color1: parseColor( dataset.color1 ),
- color2: parseColor( dataset.color2 ),
- color3: parseColor( dataset.color3 ),
- color4: parseColor( dataset.color4 ),
+ color1: dataset.color1,
+ color2: dataset.color2,
+ color3: dataset.color3,
+ color4: dataset.color4,
};
twgl.bindFramebufferInfo( gl, textureInfo );
@@ -229,9 +241,15 @@
/**
* Draw the liquid effect to the canvas.
*
- * @param {WebGLRenderingContext} gl WebGL rendering context
- * @param {Object} state Data state for the rendering frame
- * @param {Object} program Collection of program info and buffers
+ * @param {WebGLRenderingContext} gl WebGL rendering context.
+ * @param {Object} state Data state for the rendering frame.
+ * @param {Dataset} state.dataset Dataset to use for rendering.
+ * @param {number[]} state.mouse Mouse position [ x, y ].
+ * @param {number} state.time Current program time.
+ * @param {Object} program Collection of program info and buffers.
+ * @param {Object} program.programInfoEffectPass Effect pass program info.
+ * @param {Object} program.screenBufferInfo Screen buffer info.
+ * @param {Object} program.textureInfo Texture info.
*/
function renderLiquidEffect(
gl,
@@ -239,9 +257,7 @@
{ programInfoEffectPass, screenBufferInfo, textureInfo }
) {
const resolution = [ gl.canvas.width, gl.canvas.height ];
- const complexity = Number.parseInt( dataset.complexity, 10 );
- const mouseSpeed = Number.parseFloat( dataset.mouseSpeed );
- const fluidSpeed = Number.parseFloat( dataset.fluidSpeed );
+ const { complexity, mouseSpeed, fluidSpeed } = dataset;
const uniforms = {
// Required in the vertex shader to prevent stretching
@@ -278,6 +294,36 @@
}
return {
+ /**
+ * Convert a hex color string to a WebGL color vector.
+ *
+ * @param {string} color Hex color string (#FFFFFF or #FFF)
+ * @return {number[]} RGB array for WebGL
+ */
+ parseColor( color ) {
+ let r = '0';
+ let g = '0';
+ let b = '0';
+
+ if ( color.length === 7 ) {
+ r = '0x' + color[ 1 ] + color[ 2 ];
+ g = '0x' + color[ 3 ] + color[ 4 ];
+ b = '0x' + color[ 5 ] + color[ 6 ];
+ } else if ( color.length === 4 ) {
+ r = '0x' + color[ 1 ] + color[ 1 ];
+ g = '0x' + color[ 2 ] + color[ 2 ];
+ b = '0x' + color[ 3 ] + color[ 3 ];
+ }
+
+ return [ r / 0xff, g / 0xff, b / 0xff ];
+ },
+
+ /**
+ * Render a 512x512 px frame of the animation to use as a preview.
+ *
+ * @param {Dataset} dataset Dataset to use for rendering.
+ * @return {string} Data URI of a rendered frame.
+ */
renderPreview( dataset ) {
const canvas = document.createElement( 'canvas' );
canvas.width = canvas.height = '512';
@@ -296,7 +342,14 @@
return gl.canvas.toDataURL();
},
- run( canvas ) {
+
+ /**
+ * Runs the animation.
+ *
+ * @param {HTMLCanvasElement} canvas Canvas to draw on.
+ * @param {Dataset} dataset Reference to a parsed dataset.
+ */
+ run( canvas, dataset ) {
const shouldAnimate = ! window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
@@ -315,7 +368,7 @@
const program = init( gl );
const state = {
- dataset: canvas.dataset,
+ dataset,
mouse: [ 0, 0 ],
time: window.performance.now(),
rafId: 0,