UNPKG

@lightningjs/renderer

Version:
134 lines (130 loc) 4.69 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2023 Comcast Cable Communications Management, LLC. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { getNormalizedRgbaComponents } from '../../../../lib/utils.js'; import { updateFloat32ArrayLengthN } from './EffectUtils.js'; import { ShaderEffect, } from './ShaderEffect.js'; /** * Linear Gradient effect over a effect mask */ export class LinearGradientEffect extends ShaderEffect { static z$__type__Props; name = 'linearGradient'; static getEffectKey(props) { if (props.colors.value) { return `linearGradient${props.colors.value .length}`; } return `linearGradient${props.colors.length}`; } static resolveDefaults(props) { const colors = props.colors ?? [0xff000000, 0xffffffff]; let stops = props.stops || []; if (stops.length === 0 || stops.length !== colors.length) { const colorsL = colors.length; let i = 0; const tmp = stops; for (; i < colorsL; i++) { if (stops[i]) { tmp[i] = stops[i]; if (stops[i - 1] === undefined && tmp[i - 2] !== undefined) { tmp[i - 1] = tmp[i - 2] + (stops[i] - tmp[i - 2]) / 2; } } else { tmp[i] = i * (1 / (colors.length - 1)); } } stops = tmp; } return { colors, stops, angle: props.angle ?? 0, }; } static uniforms = { angle: { value: 0, method: 'uniform1f', type: 'float', }, colors: { value: 0xffffffff, validator: (rgbas) => { return rgbas.reduce((acc, val) => acc.concat(getNormalizedRgbaComponents(val)), []); }, updateProgramValue: updateFloat32ArrayLengthN, size: (props) => props.colors.length, method: 'uniform4fv', type: 'vec4', }, stops: { value: [], size: (props) => props.colors.length, method: 'uniform1fv', type: 'float', }, }; static methods = { calcPoint: ` vec2 function(float d, float angle) { return d * vec2(cos(angle), sin(angle)) + (u_dimensions * 0.5); } `, }; static ColorLoop = (amount) => { let loop = ''; for (let i = 2; i < amount; i++) { loop += `colorOut = mix(colorOut, colors[${i}], clamp((dist - stops[${i - 1}]) / (stops[${i}] - stops[${i - 1}]), 0.0, 1.0));`; } return loop; }; static onColorize = (props) => { const colors = props.colors.length || 1; return ` float a = angle - (PI / 180.0 * 90.0); float lineDist = abs(u_dimensions.x * cos(a)) + abs(u_dimensions.y * sin(a)); vec2 f = $calcPoint(lineDist * 0.5, a); vec2 t = $calcPoint(lineDist * 0.5, a + PI); vec2 gradVec = t - f; float dist = dot(v_nodeCoordinate.xy * u_dimensions - f, gradVec) / dot(gradVec, gradVec); //return early if dist is lower or equal to first stop if(dist <= stops[0]) { return mix(maskColor, colors[0], clamp(colors[0].a, 0.0, 1.0)); } const int amount = ${colors}; const int last = amount - 1; if(dist >= stops[last]) { return mix(maskColor, colors[last], clamp(colors[last].a, 0.0, 1.0)); } for(int i = 0; i < last; i++) { float left = stops[i]; float right = stops[i + 1]; if(dist >= left && dist <= right) { float localDist = smoothstep(left, right, dist); vec4 colorOut = mix(colors[i], colors[i + 1], localDist); return mix(maskColor, colorOut, clamp(colorOut.a, 0.0, 1.0)); } } //final fallback return mix(maskColor, colors[last], clamp(colors[last].a, 0.0, 1.0)); `; }; } //# sourceMappingURL=LinearGradientEffect.js.map