import type { Graph, GraphNode } from '../graph/Graph'; import { type PropertyBag, textOf } from '../model/Properties'; import { declaredNumberRows, PROPERTY_NAME_PARAM } from './declaredRows'; import { type FlatDef, isSpriteProp, isValidFieldName } from './PropertySchema'; export { PROPERTY_DEFAULT_PARAM, PROPERTY_MAX_PARAM, PROPERTY_MIN_PARAM, PROPERTY_NAME_PARAM, } from './declaredRows'; /** The sprite property naming the shader asset it wears; `''` is no shader and no render pass. */ export const SHADER_KEY = 'shader'; /** * The node of a shader graph that declares a parameter: its `name` is a sprite property and a * GLSL uniform, `default`/`min`/`max` are the row the inspector shows. */ export const SHADER_PROPERTY = 'ShaderProperty'; export function shaderOf(bag: PropertyBag): string { return textOf(bag[SHADER_KEY]); } export function isPropertyNode(node: GraphNode): boolean { return node.type === SHADER_PROPERTY; } export function propertyName(node: GraphNode): string { return textOf(node.params[PROPERTY_NAME_PARAM] ?? ''); } /** * A property's name is a bag key and a uniform, so it has to be an identifier – and not one of the * rows the sprite brings itself: both rows would share the key and the uniform would read the * sprite's width instead of the declared default (#63). The compiler names which of the two it is. */ export function isValidPropertyName(name: string): boolean { return isValidFieldName(name) && !isSpriteProp(name); } /** The properties a shader graph declares: one row on the sprite and one uniform each. */ export function shaderParamDefs(graph: Graph): FlatDef<'number'>[] { return declaredNumberRows(graph, { isDeclaration: isPropertyNode, nameOf: propertyName, isValidName: isValidPropertyName, }); } /** What a property placed from the palette is called: `value`, then `value2`, `value3` … */ export function nextPropertyName(graph: Graph): string { const taken = new Set(graph.nodes.filter(isPropertyNode).map(propertyName)); if (!taken.has('value')) return 'value'; for (let n = 2; ; n++) if (!taken.has(`value${n}`)) return `value${n}`; }