UNPKG

@polygonjs/polygonjs

Version:

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

160 lines (146 loc) 5.36 kB
/** * compares 2 input values and generates a boolean value * * @remarks * * This node is frequently used with the [js/TwoWaySwitch](/docs/nodes/js/TwoWaySwitch) * */ import {TypedJsNode} from './_Base'; import {ParamConfig, NodeParamsConfig} from '../utils/params/ParamsConfig'; import {JsConnectionPointType, JsConnectionPointTypeFromArrayTypeMap} from '../utils/io/connections/Js'; import {JsLinesCollectionController} from './code/utils/JsLinesCollectionController'; import {createVariable} from './code/assemblers/_BaseJsPersistedConfigUtils'; import {componentsForType} from '../../functions/_VectorUtils'; const ALLOWED_TYPES = [ JsConnectionPointType.BOOLEAN, JsConnectionPointType.INT, JsConnectionPointType.COLOR, JsConnectionPointType.FLOAT, JsConnectionPointType.STRING, JsConnectionPointType.VECTOR2, JsConnectionPointType.VECTOR3, JsConnectionPointType.VECTOR4, ]; export enum JsCompareTestName { EQUAL = 'Equal', LESS_THAN = 'Less Than', GREATER_THAN = 'Greater Than', LESS_THAN_OR_EQUAL = 'Less Than Or Equal', GREATER_THAN_OR_EQUAL = 'Greater Than Or Equal', NOT_EQUAL = 'Not Equal', } enum JsCompareTestOperation { EQUAL = '==', LESS_THAN = '<', GREATER_THAN = '>', LESS_THAN_OR_EQUAL = '<=', GREATER_THAN_OR_EQUAL = '>=', NOT_EQUAL = '!=', } const TEST_NAMES: JsCompareTestName[] = [ JsCompareTestName.EQUAL, JsCompareTestName.LESS_THAN, JsCompareTestName.GREATER_THAN, JsCompareTestName.LESS_THAN_OR_EQUAL, JsCompareTestName.GREATER_THAN_OR_EQUAL, JsCompareTestName.NOT_EQUAL, ]; const TEST_OPERATIONS_FLOAT: JsCompareTestOperation[] = [ JsCompareTestOperation.EQUAL, JsCompareTestOperation.LESS_THAN, JsCompareTestOperation.GREATER_THAN, JsCompareTestOperation.LESS_THAN_OR_EQUAL, JsCompareTestOperation.GREATER_THAN_OR_EQUAL, JsCompareTestOperation.NOT_EQUAL, ]; function singleElementComparison(value0: string, value1: string, operation: JsCompareTestOperation) { return `${value0} ${operation} ${value1}`; } const OUTPUT_NAME = 'val'; enum CompareInputName { VALUE0 = 'value0', VALUE1 = 'value1', } // const EXPECTED_INPUT_NAMES = ['value0', 'value1']; class CompareJsParamsConfig extends NodeParamsConfig { test = ParamConfig.INTEGER(1, { menu: { entries: TEST_NAMES.map((name, i) => { const operator = TEST_OPERATIONS_FLOAT[i]; const label = `${operator.padEnd(2, ' ')} (${name})`; return {name: label, value: i}; }), }, }); } const ParamsConfig = new CompareJsParamsConfig(); export class CompareJsNode extends TypedJsNode<CompareJsParamsConfig> { override paramsConfig = ParamsConfig; static override type() { return 'compare'; } override initializeNode() { super.initializeNode(); this.io.connection_points.spare_params.setInputlessParamNames(['test']); this.io.connection_points.initializeNode(); this.io.connection_points.set_input_name_function(this._expectedInputName.bind(this)); this.io.connection_points.set_output_name_function(this._expectedOutputName.bind(this)); this.io.connection_points.set_expected_input_types_function(this._expectedInputTypes.bind(this)); this.io.connection_points.set_expected_output_types_function(this._expectedOutputTypes.bind(this)); } setTestName(test: JsCompareTestName) { this.p.test.set(TEST_NAMES.indexOf(test)); } testName() { return TEST_NAMES[this.pv.test]; } operator() { return TEST_OPERATIONS_FLOAT[this.pv.test]; } protected _expectedInputName(index: number) { return [CompareInputName.VALUE0, CompareInputName.VALUE1][index]; } protected _expectedInputTypes() { let first_input_type = this.io.connection_points.first_input_connection_type(); const connectionPoints = this.io.inputs.namedInputConnectionPoints(); if (first_input_type && connectionPoints) { if (!ALLOWED_TYPES.includes(first_input_type)) { // if the first input type is not allowed, either leave the connection point as is, // or use the default if there is none const first_connection = connectionPoints[0]; if (first_connection) { first_input_type = first_connection.type(); } } } const type = first_input_type || JsConnectionPointType.FLOAT; const boundType = JsConnectionPointTypeFromArrayTypeMap[type]; return [type, boundType]; } private _expectedOutputTypes() { return [JsConnectionPointType.BOOLEAN]; } private _expectedOutputName(index: number) { return OUTPUT_NAME; } override setLines(shadersCollectionController: JsLinesCollectionController) { const varName = this.jsVarName(this._expectedOutputName(0)); const inputType = this._expectedInputTypes()[0]; const variable = createVariable(inputType); if (variable) { shadersCollectionController.addVariable(this, variable); } const operation = this.operator(); const value0 = this.variableForInput(shadersCollectionController, CompareInputName.VALUE0); const value1 = this.variableForInput(shadersCollectionController, CompareInputName.VALUE1); const components = componentsForType(inputType); const mainFunction = components != null && components.length > 0 ? components .map((c) => singleElementComparison(`${value0}.${c}`, `${value1}.${c}`, operation)) .join(' && ') : singleElementComparison(value0, value1, operation); shadersCollectionController.addBodyOrComputed(this, [{dataType: inputType, varName, value: mainFunction}]); } }