UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

262 lines (247 loc) 8.62 kB
/** * generates an easing function * * * @remarks * * Easing are powerful functions and can be used in many use cases, such as: * - when animating objects, vertices, or any value * - when interpolating between values, such as colors * - when modifying the shape of an object * */ import {TypedGlNode} from './_Base'; import {COMPONENTS_BY_GL_TYPE, ThreeToGl} from '../../../../src/core/ThreeToGl'; // https://github.com/glslify/glsl-easings import CircularInOut from './gl/easing/circular-in-out.glsl'; import ExponentialInOut from './gl/easing/exponential-in-out.glsl'; import CircularIn from './gl/easing/circular-in.glsl'; import ElasticOut from './gl/easing/elastic-out.glsl'; import CubicIn from './gl/easing/cubic-in.glsl'; import ExponentialOut from './gl/easing/exponential-out.glsl'; import QuinticOut from './gl/easing/quintic-out.glsl'; import ElasticInOut from './gl/easing/elastic-in-out.glsl'; import Linear from './gl/easing/linear.glsl'; import CircularOut from './gl/easing/circular-out.glsl'; import BackInOut from './gl/easing/back-in-out.glsl'; import BackIn from './gl/easing/back-in.glsl'; import SineIn from './gl/easing/sine-in.glsl'; import BackOut from './gl/easing/back-out.glsl'; import QuarticInOut from './gl/easing/quartic-in-out.glsl'; import QuadraticIn from './gl/easing/quadratic-in.glsl'; import CubicInOut from './gl/easing/cubic-in-out.glsl'; import ElasticIn from './gl/easing/elastic-in.glsl'; import BounceOut from './gl/easing/bounce-out.glsl'; import QuadraticInOut from './gl/easing/quadratic-in-out.glsl'; import ExponentialIn from './gl/easing/exponential-in.glsl'; import QuinticInOut from './gl/easing/quintic-in-out.glsl'; import SineInOut from './gl/easing/sine-in-out.glsl'; import CubicOut from './gl/easing/cubic-out.glsl'; import QuadraticOut from './gl/easing/quadratic-out.glsl'; import BounceInOut from './gl/easing/bounce-in-out.glsl'; import QuinticIn from './gl/easing/quintic-in.glsl'; import QuarticIn from './gl/easing/quartic-in.glsl'; import QuarticOut from './gl/easing/quartic-out.glsl'; import BounceIn from './gl/easing/bounce-in.glsl'; import SineOut from './gl/easing/sine-out.glsl'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {GlConnectionPointType, GlConnectionPoint} from '../utils/io/connections/Gl'; import {ShadersCollectionController} from './code/utils/ShadersCollectionController'; import {FunctionGLDefinition} from './utils/GLDefinition'; import {PolyDictionary} from '../../../types/GlobalTypes'; const EASE_NAMES = [ 'back-in-out', 'back-in', 'back-out', 'bounce-in-out', 'bounce-in', 'bounce-out', 'circular-in-out', 'circular-in', 'circular-out', 'cubic-in-out', 'cubic-in', 'cubic-out', 'elastic-in-out', 'elastic-in', 'elastic-out', 'exponential-in-out', 'exponential-in', 'exponential-out', 'linear', 'quadratic-in-out', 'quadratic-in', 'quadratic-out', // "quartic-in-out", // "quartic-in", // "quartic-out", // "quintic-in-out", // "quintic-in", // "quintic-out", 'sine-in-out', 'sine-in', 'sine-out', ]; const IMPORT_BY_EASE_NAME: PolyDictionary<string> = { 'circular-in-out': CircularInOut, 'exponential-in-out': ExponentialInOut, 'circular-in': CircularIn, 'elastic-out': ElasticOut, 'cubic-in': CubicIn, 'exponential-out': ExponentialOut, 'quintic-out': QuinticOut, 'elastic-in-out': ElasticInOut, linear: Linear, 'circular-out': CircularOut, 'back-in-out': BackInOut, 'back-in': BackIn, 'sine-in': SineIn, 'back-out': BackOut, 'quartic-in-out': QuarticInOut, 'quadratic-in': QuadraticIn, 'cubic-in-out': CubicInOut, 'elastic-in': ElasticIn, 'bounce-out': BounceOut, 'quadratic-in-out': QuadraticInOut, 'exponential-in': ExponentialIn, 'quintic-in-out': QuinticInOut, 'sine-in-out': SineInOut, 'cubic-out': CubicOut, 'quadratic-out': QuadraticOut, 'bounce-in-out': BounceInOut, 'quintic-in': QuinticIn, 'quartic-in': QuarticIn, 'quartic-out': QuarticOut, 'bounce-in': BounceIn, 'sine-out': SineOut, }; const IMPORT_DEPENDENCIES_BY_EASE_NAME: PolyDictionary<string[]> = { 'bounce-in': [BounceOut], 'bounce-in-out': [BounceOut], }; const METHOD_NAMES_BY_EASE_NAME: PolyDictionary<string> = { 'circular-in-out': 'circularInOut', 'exponential-in-out': 'exponentialInOut', 'circular-in': 'circularIn', 'elastic-out': 'elasticOut', 'cubic-in': 'cubicIn', 'exponential-out': 'exponentialOut', 'quintic-out': 'quinticOut', 'elastic-in-out': 'elasticInOut', linear: 'linear', 'circular-out': 'circularOut', 'back-in-out': 'backInOut', 'back-in': 'backIn', 'sine-in': 'sineIn', 'back-out': 'backOut', 'quartic-in-out': 'quarticInOut', 'quadratic-in': 'quadraticIn', 'cubic-in-out': 'cubicInOut', 'elastic-in': 'elasticIn', 'bounce-out': 'bounceOut', 'quadratic-in-out': 'quadraticInOut', 'exponential-in': 'exponentialIn', 'quintic-in-out': 'quinticInOut', 'sine-in-out': 'sineInOut', 'cubic-out': 'cubicOut', 'quadratic-out': 'quadraticOut', 'bounce-in-out': 'bounceInOut', 'quintic-in': 'quinticIn', 'quartic-in': 'quarticIn', 'quartic-out': 'quarticOut', 'bounce-in': 'bounceIn', 'sine-out': 'sineOut', }; const ALLOWED_INPUTS: GlConnectionPointType[] = [ GlConnectionPointType.FLOAT, GlConnectionPointType.VEC2, GlConnectionPointType.VEC3, GlConnectionPointType.VEC4, ]; const INPUT_NAME = 'in'; const OUTPUT_NAME = 'out'; const default_ease_type = EASE_NAMES.indexOf('sine-in-out'); class EasingGlParamsConfig extends NodeParamsConfig { type = ParamConfig.INTEGER(default_ease_type, { menu: { entries: EASE_NAMES.map((name, i) => { return {name: name, value: i}; }), }, }); // input = ParamConfig.FLOAT(0); } const ParamsConfig = new EasingGlParamsConfig(); export class EasingGlNode extends TypedGlNode<EasingGlParamsConfig> { override paramsConfig = ParamsConfig; static override type() { return 'easing'; } override initializeNode() { super.initializeNode(); this.io.connection_points.spare_params.setInputlessParamNames(['type']); this.io.connection_points.set_expected_input_types_function(this._expected_input_types.bind(this)); this.io.connection_points.set_expected_output_types_function(this._expected_output_types.bind(this)); this.io.connection_points.set_input_name_function(this._gl_input_name.bind(this)); this.io.connection_points.set_output_name_function(this._gl_output_name.bind(this)); this.io.outputs.setNamedOutputConnectionPoints([ new GlConnectionPoint(OUTPUT_NAME, GlConnectionPointType.FLOAT), ]); } private _expected_input_types() { const type = this.io.connection_points.first_input_connection_type() || GlConnectionPointType.FLOAT; if (ALLOWED_INPUTS.includes(type)) { return [type]; } else { return [GlConnectionPointType.FLOAT]; } } private _expected_output_types() { return [this._expected_input_types()[0]]; } _gl_input_name(index: number): string { return INPUT_NAME; } _gl_output_name(index: number): string { return OUTPUT_NAME; } override setLines(shaders_collection_controller: ShadersCollectionController) { const easeName = EASE_NAMES[this.pv.type]; const glslFunctionCode = IMPORT_BY_EASE_NAME[easeName]; let easeFunctions = [new FunctionGLDefinition(this, glslFunctionCode)]; const functionDependencies = (IMPORT_DEPENDENCIES_BY_EASE_NAME[easeName] || []).map( (f) => new FunctionGLDefinition(this, f) ); if (functionDependencies) { easeFunctions = functionDependencies.concat(easeFunctions); } // ease_functions.forEach(ease_function=>{ // function_declaration_lines.push(ease_function) // }) shaders_collection_controller.addDefinitions(this, easeFunctions); shaders_collection_controller.addBodyLines(this, this._buildBodyLines(easeName)); } private _buildBodyLines(easeName: string): string[] { const functionName = METHOD_NAMES_BY_EASE_NAME[easeName]; const outValue = this.glVarName(OUTPUT_NAME); const outGlType = this._expected_output_types()[0]; switch (outGlType) { case GlConnectionPointType.FLOAT: { const inValue = ThreeToGl.float(this.variableForInput(INPUT_NAME)); return [`${outGlType} ${outValue} = ${functionName}(${inValue})`]; } default: { const bodyLines: string[] = []; const inValue = ThreeToGl.glType(outGlType, this.variableForInput(INPUT_NAME)); const components = COMPONENTS_BY_GL_TYPE[outGlType]; if (components) { const args = components.map((c) => `${functionName}(${inValue}.${c})`).join(', '); bodyLines.push(`${outGlType} ${outValue} = ${outGlType}(${args})`); return bodyLines; } else { return []; } } } } }