/* * 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. * * SPDX-License-Identifier: Apache-2.0 */ import type { CoreNode } from '../../CoreNode.js'; import { normalizeCanvasColor } from '../../lib/colorCache.js'; import type { Stage } from '../../Stage.js'; import { CoreShaderNode, type CoreShaderType } from '../CoreShaderNode.js'; export type CanvasShaderType< T extends object = Record, C extends object = Record, > = CoreShaderType & { render: ( this: CanvasShaderNode, ctx: CanvasRenderingContext2D, node: CoreNode, renderContext: () => void, ) => void; update?: (this: CanvasShaderNode, node: CoreNode) => void; /** * Set this to true when using ctx functions that scale, clip, rotate, etc.. */ saveAndRestore?: boolean; }; export class CanvasShaderNode< Props extends object = Record, Computed extends object = Record, > extends CoreShaderNode { private updater: ((node: CoreNode, props?: Props) => void) | undefined = undefined; private valueKey: string = ''; computed: Partial = {}; applySNR: boolean; render: CanvasShaderType['render']; constructor( shaderKey: string, config: CanvasShaderType, stage: Stage, props?: Props, ) { super(shaderKey, config, stage, props); this.applySNR = config.saveAndRestore || false; this.render = config.render; if (config.update !== undefined) { this.updater = config.update!; if (this.props === undefined) { this.updater!(this.node as CoreNode, this.props); return; } this.update = () => { const prevKey = this.valueKey; this.valueKey = this.createValueKey(); if (prevKey === this.valueKey) { return; } if (prevKey.length > 0) { stage.shManager.mutateShaderValueUsage(prevKey, -1); } const computed = stage.shManager.getShaderValues( this.valueKey, ) as Record; if (computed !== undefined) { this.computed = computed as Computed; } this.computed = {}; this.updater!(this.node as CoreNode); stage.shManager.setShaderValues(this.valueKey, this.computed); }; } } toColorString(rgba: number) { return normalizeCanvasColor(rgba, true); } }