@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
791 lines (744 loc) • 27.5 kB
text/typescript
import {ShaderMaterial} from 'three';
import {LineType} from '../utils/LineType';
import {VariableConfig} from '../configs/VariableConfig';
import {JsCodeBuilder, CodeBuilderSetCodeLinesOptions} from '../utils/CodeBuilder';
import {BaseJsNodeType, TypedJsNode} from '../../_Base';
import {JsShaderConfig} from '../configs/ShaderConfig';
import {TypedAssembler} from '../../../utils/shaders/BaseAssembler';
import {JsFunctionName} from '../../../utils/shaders/ShaderName';
import {OutputJsNode} from '../../Output';
import {JsConnectionPoint, JsConnectionPointType} from '../../../utils/io/connections/Js';
import {GlobalsJsNode} from '../../Globals';
import {AttributeJsNode} from '../../Attribute';
import {AssemblerControllerNode} from '../Controller';
import {GlobalsJsBaseController} from '../globals/_Base';
import {JsLinesCollectionController} from '../utils/JsLinesCollectionController';
import {NodeContext} from '../../../../poly/NodeContext';
import {TypedNodeTraverser} from '../../../utils/shaders/NodeTraverser';
import {JsNodeFinder} from '../utils/NodeFinder';
import {JsType} from '../../../../poly/registers/nodes/types/Js';
import {BaseNamedFunction} from '../../../../functions/_Base';
import {RegisterableVariable} from './_BaseJsPersistedConfigUtils';
import {NamedFunctionMap} from '../../../../poly/registers/functions/All';
import {JsParamConfig} from '../utils/JsParamConfig';
import {ParamType} from '../../../../poly/ParamType';
import {ParamOptions} from '../../../../params/utils/OptionsController';
import {SopType} from '../../../../poly/registers/nodes/types/Sop';
type StringArrayByJsFunctionName = Map<JsFunctionName, string[]>;
export interface SpareParamOptions {
type: ParamType;
}
export interface BaseFunctionData {
variableNames: string[];
variablesByName: Record<string, RegisterableVariable>;
functionNames: Array<keyof NamedFunctionMap>;
functionsByName: Record<string, Function>;
paramConfigs: JsParamConfig<ParamType>[];
}
export interface VelocityColliderFunctionBody {
velocity: string;
collider: string;
}
export interface SingleBodyFunctionData extends BaseFunctionData {
functionBody: string;
}
export interface VelocityColliderFunctionData extends BaseFunctionData {
functionBody: VelocityColliderFunctionBody;
}
interface JsTemplateShader {
main?: string;
velocity?: string;
collider?: string;
// uniforms?: IUniforms;
}
export const INSERT_MEMBERS_AFTER = '// insert members';
export const INSERT_DEFINE_AFTER = '// insert defines';
export const INSERT_CONSTRUCTOR_AFTER = '// insert after constructor';
export const INSERT_BODY_AFTER = '// insert body';
// export const INSERT_TRIGGER_AFTER = '// insert trigger';
// export const INSERT_TRIGGERABLE_AFTER = '// insert triggerable';
const INSERT_MEMBER_AFTER_MAP: Map<JsFunctionName, string> = new Map([
// [ShaderName.VERTEX, '#include <common>'],
[JsFunctionName.MAIN, INSERT_MEMBERS_AFTER],
[JsFunctionName.VELOCITY, INSERT_MEMBERS_AFTER],
[JsFunctionName.COLLIDER, INSERT_MEMBERS_AFTER],
]);
const INSERT_DEFINE_AFTER_MAP: Map<JsFunctionName, string> = new Map([
// [ShaderName.VERTEX, '#include <common>'],
[JsFunctionName.MAIN, INSERT_DEFINE_AFTER],
[JsFunctionName.VELOCITY, INSERT_DEFINE_AFTER],
[JsFunctionName.COLLIDER, INSERT_DEFINE_AFTER],
]);
const INSERT_CONSTRUCTOR_AFTER_MAP: Map<JsFunctionName, string> = new Map([
// [ShaderName.VERTEX, '#include <common>'],
[JsFunctionName.MAIN, INSERT_CONSTRUCTOR_AFTER],
[JsFunctionName.VELOCITY, INSERT_CONSTRUCTOR_AFTER],
[JsFunctionName.COLLIDER, INSERT_CONSTRUCTOR_AFTER],
]);
const INSERT_BODY_AFTER_MAP: Map<JsFunctionName, string> = new Map([
// [ShaderName.VERTEX, '#include <color_vertex>'],
[JsFunctionName.MAIN, INSERT_BODY_AFTER],
[JsFunctionName.VELOCITY, INSERT_BODY_AFTER],
[JsFunctionName.COLLIDER, INSERT_BODY_AFTER],
]);
// const INSERT_TRIGGER_AFTER_MAP: Map<ShaderName, string> = new Map([
// // [ShaderName.VERTEX, '#include <color_vertex>'],
// [ShaderName.FRAGMENT, INSERT_TRIGGER_AFTER],
// ]);
// const INSERT_TRIGGERABLE_AFTER_MAP: Map<ShaderName, string> = new Map([
// // [ShaderName.VERTEX, '#include <color_vertex>'],
// [ShaderName.FRAGMENT, INSERT_TRIGGERABLE_AFTER],
// ]);
const LINES_TO_REMOVE_MAP: Map<JsFunctionName, string[]> = new Map([
// [ShaderName.VERTEX, ['#include <begin_vertex>', '#include <beginnormal_vertex>']],
[JsFunctionName.MAIN, []],
[JsFunctionName.VELOCITY, []],
[JsFunctionName.COLLIDER, []],
]);
const SPACED_LINES = 3;
const PER_POINT_PARENT_TYPES: Set<string> = new Set([SopType.ACTOR_INSTANCE, SopType.ACTOR_POINT]);
export abstract class BaseJsShaderAssembler extends TypedAssembler<NodeContext.JS> {
protected _shaders_by_name: Map<JsFunctionName, string> = new Map();
protected _lines: StringArrayByJsFunctionName = new Map();
protected _codeBuilder: JsCodeBuilder | undefined;
private _param_config_owner: JsCodeBuilder | undefined;
protected _root_nodes: BaseJsNodeType[] = [];
protected _leaf_nodes: BaseJsNodeType[] = [];
protected _material: ShaderMaterial | undefined;
private _shader_configs: JsShaderConfig[] | undefined;
private _variable_configs: VariableConfig[] | undefined;
private _uniformsTimeDependent: boolean = false;
private _uniformsResolutionDependent: boolean = false;
private _computedVarNames: Set<string> = new Set();
constructor(protected _jsParentNode: AssemblerControllerNode<BaseJsShaderAssembler>) {
super();
}
perPoint() {
return PER_POINT_PARENT_TYPES.has(this._jsParentNode.type());
}
protected _overridenJsParentNode: AssemblerControllerNode<BaseJsShaderAssembler> | undefined;
setJsParentNode(parentNode: AssemblerControllerNode<BaseJsShaderAssembler>) {
this._overridenJsParentNode = parentNode;
}
currentJsParentNode() {
return this._overridenJsParentNode || this._jsParentNode;
}
abstract makeFunctionNodeDirtyOnChange(): boolean;
addComputedVarName(varName: string) {
if (!this.computedVariablesAllowed()) {
return;
}
this._computedVarNames.add(varName);
}
registeredAsComputed(varName: string): boolean {
if (varName.trim().length == 0) {
console.warn(`attempt to read an empty variable ('${varName}')`);
}
return this._computedVarNames.has(varName);
}
computedVariablesAllowed(): boolean {
return false;
}
memberReference(varName: string): string {
if (this.computedVariablesAllowed()) {
return `this.${varName}.value`;
} else {
return `this.${varName}`;
}
}
abstract spareParamsOptions(options: SpareParamOptions): ParamOptions;
compile() {}
abstract defaultObjectVariable(): string;
abstract defaultObject3DMaterialVariable(): string;
abstract defaultPrimitiveGraph(): string;
// abstract defaultEntityIndexVariable(): string;
// private get material() {
// return (this._material = this._material || this._createMaterial());
// }
// async get_material(/*master_assembler?: BaseGlShaderAssembler*/) {
// this._material = this._material || this._createMaterial();
// await this._update_material(/*master_assembler*/);
// return this._material;
// }
protected _template_shader_for_shader_name(shaderName: JsFunctionName): string | undefined {
switch (shaderName) {
case JsFunctionName.MAIN:
return this.templateShader()?.main;
case JsFunctionName.VELOCITY:
return this.templateShader()?.velocity;
case JsFunctionName.COLLIDER:
return this.templateShader()?.collider;
}
}
globalsHandler(): GlobalsJsBaseController | undefined {
return this.currentJsParentNode().assemblerController()?.globalsHandler();
}
compileAllowed(): boolean {
return this.currentJsParentNode().assemblerController()?.globalsHandler() != null;
}
shaders_by_name() {
return this._shaders_by_name;
}
// protected createMaterial(): ShaderMaterial | undefined {
// return undefined;
// }
protected _buildLines() {
for (const shaderName of this.shaderNames()) {
const template = this._template_shader_for_shader_name(shaderName);
if (template) {
this._replaceTemplate(template, shaderName);
}
}
}
// protected _build_lines_for_shader_name(shader_name: ShaderName){
// const template = this._template_shader()
// this._replace_template(template[`${shader_name}Shader`], shader_name)
// }
set_root_nodes(root_nodes: BaseJsNodeType[]) {
this._root_nodes = root_nodes;
}
protected templateShader(): JsTemplateShader | undefined {
return undefined;
}
protected _reset() {
this._resetRegisteredFunctions();
this._resetRegisteredVariables();
this._computedVarNames.clear();
}
updateFunction() {
this._reset();
}
// protected addUniforms(uniforms: IUniforms) {
// for (let param_config of this.param_configs()) {
// uniforms[param_config.uniformName()] = param_config.uniform();
// }
// if (this.uniformsTimeDependent()) {
// uniforms[UniformName.TIME] = uniforms[UniformName.TIME] || {
// // type: '1f',
// value: this.currentGlParentNode().scene().time(),
// };
// }
// if (this.uniformsResolutionDependent()) {
// uniforms[UniformName.RESOLUTION] = uniforms[UniformName.RESOLUTION] || {
// value: new Vector2(1000, 1000),
// };
// }
// }
//
//
// ROOT NODES AND SHADER NAMES
//
//
rootNodesByShaderName(shaderName: JsFunctionName, rootNodes: BaseJsNodeType[]): BaseJsNodeType[] {
// return this._root_nodes
const list = [];
for (const node of rootNodes) {
switch (node.type()) {
// case VaryingWriteGlNode.type():
// case ParamGlNode.type():
case JsType.PARAM:
// case SubnetOutputGlNode.type():
case JsType.OUTPUT: {
list.push(node);
break;
}
case JsType.OUTPUT_AMBIENT_LIGHT:
case JsType.OUTPUT_AREA_LIGHT:
case JsType.OUTPUT_DIRECTIONAL_LIGHT:
case JsType.OUTPUT_HEMISPHERE_LIGHT:
case JsType.OUTPUT_POINT_LIGHT:
case JsType.OUTPUT_SPOT_LIGHT: {
list.push(node);
break;
}
// case SubnetOutputGlNode.type(): {
// list.push(node);
// break;
// }
// case ParamGlNode.type(): {
// list.push(node);
// break;
// }
case JsType.ATTRIBUTE: {
list.push(node);
break;
}
// case VaryingWriteGlNode.type(): {
// list.push(node);
// break;
// }
}
}
return list;
}
// leafNodesByShaderName(shaderName: ShaderName): BaseGlNodeType[] {
// const list = [];
// for (let node of this._leaf_nodes) {
// switch (node.type()) {
// case GlobalsGlNode.type(): {
// list.push(node);
// break;
// }
// case AttributeGlNode.type(): {
// break;
// }
// }
// }
// return list;
// }
setNodeLinesGlobals(globalsNode: GlobalsJsNode, linesController: JsLinesCollectionController) {}
setNodeLinesOutput(outputNode: OutputJsNode, linesController: JsLinesCollectionController) {}
setNodeLinesAttribute(attributeNode: AttributeJsNode, linesController: JsLinesCollectionController) {}
//
//
// CHILDREN NODES PARAMS
//
//
codeBuilder() {
return (this._codeBuilder = this._codeBuilder || this._createCodeBuilder());
}
private _createCodeBuilder() {
const computedVariablesAllowed = this._jsParentNode
.assemblerController()
?.assembler?.computedVariablesAllowed();
const nodeTraverser = new TypedNodeTraverser<NodeContext.JS>(
this.currentJsParentNode(),
this.shaderNames(),
(rootNode, shaderName) => {
return this.inputNamesForShaderName(rootNode, shaderName);
},
{
// we do traverse children if computed(()=>{}) is used.
// If not, we don't need to traverse children,
// and the code is handled by the subnet internal code builder
traverseChildren: computedVariablesAllowed == true ? true : false,
}
);
return new JsCodeBuilder(
nodeTraverser,
(shaderName, rootNodes) => {
return this.rootNodesByShaderName(shaderName, rootNodes);
},
this
);
}
protected buildCodeFromNodes(rootNodes: BaseJsNodeType[], codeBuilderOptions?: CodeBuilderSetCodeLinesOptions) {
const paramNodes = JsNodeFinder.findParamGeneratingNodes(this.currentJsParentNode());
this.codeBuilder().buildFromNodes(rootNodes, paramNodes, codeBuilderOptions);
}
allow_new_param_configs() {
this.codeBuilder().allow_new_param_configs();
}
disallow_new_param_configs() {
this.codeBuilder().disallow_new_param_configs();
}
builder_param_configs() {
return this.codeBuilder().param_configs();
}
builder_lines(shader_name: JsFunctionName, line_type: LineType) {
return this.codeBuilder().lines(shader_name, line_type);
}
all_builder_lines() {
return this.codeBuilder().all_lines();
}
param_configs() {
const code_builder = this._param_config_owner || this.codeBuilder();
return code_builder.param_configs();
}
set_param_configs_owner(param_config_owner: JsCodeBuilder) {
this._param_config_owner = param_config_owner;
if (this._param_config_owner) {
this.codeBuilder().disallow_new_param_configs();
} else {
this.codeBuilder().allow_new_param_configs();
}
}
//
//
// CHILDREN NODES PARAMS
//
//
static output_input_connection_points(): JsConnectionPoint<JsConnectionPointType>[] {
return [
// new JsConnectionPoint('position', JsConnectionPointType.VEC3),
// new JsConnectionPoint('normal', JsConnectionPointType.VEC3),
// new JsConnectionPoint('color', JsConnectionPointType.VEC3),
// new JsConnectionPoint('alpha', JsConnectionPointType.FLOAT),
// new JsConnectionPoint('uv', JsConnectionPointType.VEC2),
];
}
add_output_inputs(output_child: OutputJsNode) {
output_child.io.inputs.setNamedInputConnectionPoints(BaseJsShaderAssembler.output_input_connection_points());
}
static create_globals_node_output_connections() {
// TODO: move this in material only, to use the enum GlobalsOutput
return [
// new JsConnectionPoint('position', JsConnectionPointType.VEC3),
// new JsConnectionPoint('normal', JsConnectionPointType.VEC3),
// new JsConnectionPoint('color', JsConnectionPointType.VEC3),
// new JsConnectionPoint('uv', JsConnectionPointType.VEC2),
// new JsConnectionPoint(GlobalsOutput.MV_POSITION, JsConnectionPointType.VEC4),
// // Maybe I should not add worldPosition, worldNormal, I just now
// // as those could add computation overhead when always present in the shader.
// // But hopefully in the soon future, they will only be added when the code builder
// // adds lines based on connections, as opposed to the whole node
// new JsConnectionPoint('worldPosition', JsConnectionPointType.VEC4), // vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
// new JsConnectionPoint('worldNormal', JsConnectionPointType.VEC3), // vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
// // new GlConnectionPoint('I', GlConnectionPointType.VEC3), // vec3 I = worldPosition.xyz - cameraPosition;
// new JsConnectionPoint(GlobalsOutput.GL_POSITION, JsConnectionPointType.VEC4),
// new JsConnectionPoint(GlobalsOutput.GL_FRAGCOORD, JsConnectionPointType.VEC4),
// new JsConnectionPoint('cameraPosition', JsConnectionPointType.VEC3),
// new JsConnectionPoint(GlobalsOutput.RESOLUTION, JsConnectionPointType.VEC2),
// new JsConnectionPoint(GlobalsOutput.TIME, JsConnectionPointType.FLOAT),
];
}
create_globals_node_output_connections() {
return BaseJsShaderAssembler.create_globals_node_output_connections();
}
add_globals_outputs(globals_node: GlobalsJsNode) {
globals_node.io.outputs.setNamedOutputConnectionPoints(this.create_globals_node_output_connections());
}
allow_attribute_exports() {
return false;
}
//
//
// CONFIGS
//
//
resetConfigs() {
this._reset_shader_configs();
this._reset_variable_configs();
this._resetUniformsTimeDependency();
this._resetUniformsResolutionDependency();
}
shaderConfigs() {
return (this._shader_configs = this._shader_configs || this.create_shader_configs());
}
set_shader_configs(shader_configs: JsShaderConfig[]) {
this._shader_configs = shader_configs;
}
shaderNames(): JsFunctionName[] {
return this.shaderConfigs()?.map((sc) => sc.name()) || [];
}
protected _reset_shader_configs() {
this._shader_configs = undefined;
}
create_shader_configs(): JsShaderConfig[] {
return [
// new ShaderConfig(ShaderName.VERTEX, ['position', 'normal', 'uv', VaryingWriteGlNode.INPUT_NAME], []),
new JsShaderConfig(JsFunctionName.MAIN, ['color', 'alpha'], []),
];
}
shader_config(name: string): JsShaderConfig | undefined {
return this.shaderConfigs()?.filter((sc) => {
return sc.name() == name;
})[0];
}
variable_configs() {
return (this._variable_configs = this._variable_configs || this.create_variable_configs());
}
set_variable_configs(variable_configs: VariableConfig[]) {
this._variable_configs = variable_configs;
}
variable_config(name: string) {
return this.variable_configs().filter((vc) => {
return vc.name() == name;
})[0];
}
static create_variable_configs() {
return [
new VariableConfig('d', {
// default_from_attribute: true,
// default: this.globalsHandler().variable_config_default('position'),
// required_definitions: this.globalsHandler().variable_config_required_definitions('position'),
prefix: 'return ',
}),
// new VariableConfig('normal', {
// default_from_attribute: true,
// prefix: 'vec3 objectNormal = ',
// postLines: ['#ifdef USE_TANGENT', ' vec3 objectTangent = vec3( tangent.xyz );', '#endif'],
// }),
// new VariableConfig('color', {
// prefix: 'diffuseColor.xyz = ',
// }),
// new VariableConfig('alpha', {
// prefix: 'diffuseColor.a = ',
// }),
// new VariableConfig('uv', {
// // default_from_attribute: true,
// prefix: 'vUv = ',
// // if: GlobalsGeometryHandler.IF_RULE.uv,
// }),
];
}
create_variable_configs(): VariableConfig[] {
return BaseJsShaderAssembler.create_variable_configs();
}
protected _reset_variable_configs() {
this._variable_configs = undefined;
this.variable_configs();
}
inputNamesForShaderName(rootNode: BaseJsNodeType, shaderName: JsFunctionName) {
// for simplicity,
// and to make it work with objectBuilder,
// without having to specify each output node's input names (especially for the light outputs)
// we just return all the input names
// if we are in JsFunctionName.MAIN
if (shaderName == JsFunctionName.MAIN) {
return (rootNode.io.inputs.namedInputConnectionPoints() || []).map((c) => c.name()); //this.shader_config(shader_name)?.input_names() || [];
} else {
return this.shader_config(shaderName)?.input_names() || [];
}
}
// time dependency
protected _resetUniformsTimeDependency() {
this._uniformsTimeDependent = false;
}
setUniformsTimeDependent() {
this._uniformsTimeDependent = true;
}
uniformsTimeDependent(): boolean {
return this._uniformsTimeDependent;
}
// resolution dependency
protected _resetUniformsResolutionDependency() {
this._uniformsResolutionDependent = false;
}
setUniformsResolutionDependent() {
this._uniformsResolutionDependent = true;
}
uniformsResolutionDependent(): boolean {
return this._uniformsResolutionDependent;
}
protected _raymarchingLightsWorldCoordsDependent() {
return false;
}
//
//
// TEMPLATE HOOKS
//
//
protected insertMemberAfter(shaderName: JsFunctionName): string | undefined {
return INSERT_MEMBER_AFTER_MAP.get(shaderName);
}
protected insertDefineAfter(shaderName: JsFunctionName): string | undefined {
return INSERT_DEFINE_AFTER_MAP.get(shaderName);
}
protected insertConstructorAfter(shaderName: JsFunctionName): string | undefined {
return INSERT_CONSTRUCTOR_AFTER_MAP.get(shaderName);
}
protected insertBodyAfter(shaderName: JsFunctionName): string | undefined {
return INSERT_BODY_AFTER_MAP.get(shaderName);
}
// protected insertTriggerAfter(shaderName: ShaderName): string | undefined {
// return INSERT_TRIGGER_AFTER_MAP.get(shaderName);
// }
// protected insertTriggerableAfter(shaderName: ShaderName): string | undefined {
// return INSERT_TRIGGERABLE_AFTER_MAP.get(shaderName);
// }
protected linesToRemove(shaderName: JsFunctionName): string[] | undefined {
return LINES_TO_REMOVE_MAP.get(shaderName);
}
//
//
// TEMPLATE CODE REPLACEMENT
//
//
private _replaceTemplate(template: string, shaderName: JsFunctionName) {
const memberLines = this.builder_lines(shaderName, LineType.MEMBER);
const constructorLines = this.builder_lines(shaderName, LineType.CONSTRUCTOR);
// const triggerLines = this.builder_lines(shaderName, LineType.TRIGGER);
// const triggerableLines = this.builder_lines(shaderName, LineType.TRIGGERABLE);
const defineLines = this.builder_lines(shaderName, LineType.DEFINE);
// const define = this.builder_lines(shaderName, LineType.DEFINE);
// let all_define = function_declaration.concat(define);
const body = this.builder_lines(shaderName, LineType.BODY);
let templateLines = template.split('\n');
// const scene = this.currentGlParentNode().scene;
const newLines: string[] = [
// `#define FPS ${ThreeToGl.float(scene.time_controller.fps)}`,
// `#define TIME_INCREMENT (1.0/${ThreeToGl.float(scene.time_controller.fps)})`,
// `#define FRAME_RANGE_START ${ThreeToGl.float(scene.time_controller.frame_range[0])}`,
// `#define FRAME_RANGE_END ${ThreeToGl.float(scene.time_controller.frame_range[1])}`,
];
const lineBeforeMember = this.insertMemberAfter(shaderName);
const lineBeforeDefine = this.insertDefineAfter(shaderName);
const lineBeforeConstructor = this.insertConstructorAfter(shaderName);
const lineBeforeBody = this.insertBodyAfter(shaderName);
// const lineBeforeTrigger = this.insertTriggerAfter(shaderName);
// const lineBeforeTriggerable = this.insertTriggerableAfter(shaderName);
const linesToRemove = this.linesToRemove(shaderName);
let lineBeforeMemberFound = false;
let lineBeforeDefineFound = false;
let lineBeforeConstructorFound = false;
// let lineBeforeTriggerFound = false;
// let lineBeforeTriggerableFound = false;
let lineBeforeBodyFoundOnPreviousLine = false;
let lineBeforeBodyFound = false;
for (const templateLine of templateLines) {
if (lineBeforeMemberFound == true) {
if (memberLines) {
this._insertLines(newLines, memberLines);
}
lineBeforeMemberFound = false;
}
if (lineBeforeDefineFound == true) {
if (defineLines) {
this._insertLines(newLines, defineLines);
}
lineBeforeDefineFound = false;
}
if (lineBeforeConstructorFound == true) {
if (constructorLines) {
this._insertLines(newLines, constructorLines);
}
lineBeforeConstructorFound = false;
}
// if (lineBeforeTriggerFound == true) {
// if (triggerLines) {
// this._insertLines(newLines, triggerLines);
// }
// lineBeforeTriggerFound = false;
// }
// if (lineBeforeTriggerableFound == true) {
// if (triggerableLines) {
// this._insertLines(newLines, triggerableLines);
// }
// lineBeforeTriggerableFound = false;
// }
if (lineBeforeBodyFoundOnPreviousLine == true) {
// this._insert_default_body_declarations(new_lines, shaderName)
if (body) {
this._insertLines(newLines, body);
}
lineBeforeBodyFoundOnPreviousLine = false;
}
let line_remove_required = false;
if (linesToRemove) {
for (const line_to_remove of linesToRemove) {
if (templateLine.indexOf(line_to_remove) >= 0) {
line_remove_required = true;
}
}
}
if (!line_remove_required) {
newLines.push(templateLine);
} else {
newLines.push('// removed:');
newLines.push(`//${templateLine}`);
}
if (lineBeforeDefine && templateLine.indexOf(lineBeforeDefine) >= 0) {
lineBeforeDefineFound = true;
}
if (lineBeforeConstructor && templateLine.indexOf(lineBeforeConstructor) >= 0) {
lineBeforeConstructorFound = true;
}
// if (lineBeforeTrigger && templateLine.indexOf(lineBeforeTrigger) >= 0) {
// lineBeforeTriggerFound = true;
// }
// if (lineBeforeTriggerable && templateLine.indexOf(lineBeforeTriggerable) >= 0) {
// lineBeforeTriggerableFound = true;
// }
if (lineBeforeMember && templateLine.indexOf(lineBeforeMember) >= 0) {
lineBeforeMemberFound = true;
}
if (lineBeforeBody && templateLine.indexOf(lineBeforeBody) >= 0) {
lineBeforeBodyFoundOnPreviousLine = true;
lineBeforeBodyFound = true;
}
// if(template_line.indexOf('// INSERT DEFINE') >= 0){
// } else {
// if(template_line.indexOf('// INSERT BODY') >= 0){
// if(body.length > 0){
// lodash_times(3, ()=>new_lines.push(' '))
// body.forEach(body_line=>{
// new_lines.push(body_line)
// })
// lodash_times(3, ()=>new_lines.push(' '))
// }
// } else {
// if(template_line.indexOf('// TO REMOVE') < 0){
// new_lines.push(template_line)
// }
// }
// }
}
if (lineBeforeBody) {
if (!lineBeforeBodyFound) {
console.warn(`line '${lineBeforeBody}' was not found in shader '${shaderName}'`, template, this);
} else {
// console.log(`OK: line '${line_before_body}' was found in shader '${shader_name}'`, template, this);
}
}
this._lines.set(shaderName, newLines);
}
private _insertLines(newLines: string[], linesToAdd: string[]) {
if (linesToAdd.length == 0) {
return;
}
for (let i = 0; i < SPACED_LINES; i++) {
newLines.push('');
}
for (const lineToAdd of linesToAdd) {
newLines.push(lineToAdd);
}
for (let i = 0; i < SPACED_LINES; i++) {
newLines.push('');
}
}
//
//
// REGISTERED VARIABLES
//
//
private _registeredVariables: Map<string, RegisterableVariable> = new Map();
private _registeredVariablesCountByNode: Map<BaseJsNodeType, number> = new Map();
addVariable(node: BaseJsNodeType, variable: RegisterableVariable, varName?: string): string {
// const nodeSanitizedPath = CoreString.sanitizeName(node.path());
// const varFullName = `${nodeSanitizedPath}_${varName}`;
const count = this._registeredVariablesCountByNode.get(node) || 0;
this._registeredVariablesCountByNode.set(node, count + 1);
const varFullName = varName ? varName : 'VAR_' + TypedJsNode.inputVarName(node, count == 0 ? '' : `_${count}`);
this._registeredVariables.set(varFullName, variable);
return varFullName;
}
traverseRegisteredVariables(callback: (variable: RegisterableVariable, varName: string) => void) {
this._registeredVariables.forEach(callback);
}
protected _resetRegisteredVariables() {
this._registeredVariables.clear();
this._registeredVariablesCountByNode.clear();
}
//
//
// REGISTERED FUNCTIONS
//
//
private _registeredFunctions: Map<string, BaseNamedFunction> = new Map();
addFunction(node: BaseJsNodeType, namedFunction: BaseNamedFunction) {
const existingFunctionName = this._registeredFunctions.get(namedFunction.type());
if (existingFunctionName) {
return;
}
this._registeredFunctions.set(namedFunction.type(), namedFunction);
// let i=0
// for(let _func of functions){
// const functionName= this._nameByFunctions.get(_func)
// if(!functionName){
// }
// }
// const functionDefinitions = functions.map((f,i)=>{
// const functionName=`${node.name()})_${i}`
// return new FunctionJsDefinition(node, functionName, f)
// })
// this.addDefinitions(node, functionDefinitions);
}
traverseRegisteredFunctions(callback: (variable: BaseNamedFunction) => void) {
this._registeredFunctions.forEach(callback);
}
protected _resetRegisteredFunctions() {
this._registeredFunctions.clear();
// this._nameByFunctions.clear();
}
}