UNPKG

polygonjs-engine

Version:

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

237 lines (225 loc) 8.68 kB
import {TextureAllocation, TextureAllocationData} from './TextureAllocation'; import {BaseGlNodeType} from '../../_Base'; // import {TypedConnection, COMPONENTS_COUNT_BY_TYPE} from '../../../../../Engine/Node/Gl/GlData'; import {TextureVariable} from './TextureVariable'; import {ShaderConfig} from '../configs/ShaderConfig'; import {ShaderName, ParticleShaderNames} from '../../../utils/shaders/ShaderName'; import {PolyScene} from '../../../../scene/PolyScene'; import {GlConnectionPointComponentsCountMap, BaseGlConnectionPoint} from '../../../utils/io/connections/Gl'; import {AttributeGlNode} from '../../Attribute'; import {GlobalsGlNode} from '../../Globals'; import {OutputGlNode} from '../../Output'; import {ArrayUtils} from '../../../../../core/ArrayUtils'; import {PolyDictionary} from '../../../../../types/GlobalTypes'; export type TextureAllocationsControllerData = PolyDictionary<TextureAllocationData>[]; const OUTPUT_NAME_ATTRIBUTES = ['position', 'normal', 'color', 'uv']; export class TextureAllocationsController { private _allocations: TextureAllocation[] = []; private _next_allocation_index: number = 0; constructor() {} allocate_connections_from_root_nodes(root_nodes: BaseGlNodeType[], leaf_nodes: BaseGlNodeType[]) { const variables = []; // TODO: let's go through the output node first, in case there is a name conflict, it will have priority for (let node of root_nodes) { const node_id = node.graphNodeId(); switch (node.type()) { case OutputGlNode.type(): { for (let connection_point of node.io.inputs.named_input_connection_points) { const input = node.io.inputs.named_input(connection_point.name()); if (input) { // connections_by_node_id[node_id] = connections_by_node_id[node_id] || [] // connections_by_node_id[node_id].push(named_input) const variable = new TextureVariable( connection_point.name(), GlConnectionPointComponentsCountMap[connection_point.type()] ); variable.add_graph_node_id(node_id); variables.push(variable); } } break; } case AttributeGlNode.type(): { const attrib_node = node as AttributeGlNode; const named_input: BaseGlNodeType | null = attrib_node.connected_input_node(); const connection_point: | BaseGlConnectionPoint | undefined = attrib_node.connected_input_connection_point(); if (named_input && connection_point) { // connections_by_node_id[node_id] = connections_by_node_id[node_id] || [] // connections_by_node_id[node_id].push(named_input) const variable = new TextureVariable( attrib_node.attribute_name, GlConnectionPointComponentsCountMap[connection_point.type()] ); variable.add_graph_node_id(node_id); variables.push(variable); } break; } } } for (let node of leaf_nodes) { const node_id = node.graphNodeId(); switch (node.type()) { case GlobalsGlNode.type(): { const globals_node = node as GlobalsGlNode; // const output_names_not_attributes = ['frame', 'gl_FragCoord', 'gl_PointCoord']; for (let output_name of globals_node.io.outputs.used_output_names()) { // is_attribute, as opposed to frame, gl_FragCoord and gl_PointCoord which are either uniforms or provided by the renderer const is_attribute = OUTPUT_NAME_ATTRIBUTES.includes(output_name); if (is_attribute) { const connection_point = globals_node.io.outputs.named_output_connection_points_by_name( output_name ); if (connection_point) { const gl_type = connection_point.type(); const variable = new TextureVariable( output_name, GlConnectionPointComponentsCountMap[gl_type] ); variable.add_graph_node_id(node_id); variables.push(variable); } } } break; } case AttributeGlNode.type(): { const attribute_node = node as AttributeGlNode; const connection_point = attribute_node.output_connection_point(); if (connection_point) { // connections_by_node_id[node_id] = connections_by_node_id[node_id] || [] // connections_by_node_id[node_id].push(named_output) const variable = new TextureVariable( attribute_node.attribute_name, GlConnectionPointComponentsCountMap[connection_point.type()] ); variable.add_graph_node_id(node_id); variables.push(variable); } break; } } } this.allocate_variables(variables); } private allocate_variables(variables: TextureVariable[]) { const variables_by_size_inverse = ArrayUtils.sortBy(variables, (variable) => { return -variable.size; }); for (let variable of variables_by_size_inverse) { this.allocate_variable(variable); } } private allocate_variable(new_variable: TextureVariable) { let allocated = this.has_variable(new_variable.name()); if (allocated) { const allocated_variable = this.variables().filter((v) => v.name() == new_variable.name())[0]; new_variable.graph_node_ids?.forEach((boolean, graph_node_id) => { allocated_variable.add_graph_node_id(graph_node_id); }); } else { if (!allocated) { for (let allocation of this._allocations) { if (!allocated && allocation.has_space_for_variable(new_variable)) { allocation.add_variable(new_variable); allocated = true; } } } if (!allocated) { const new_allocation = new TextureAllocation(this.next_allocation_name()); this._allocations.push(new_allocation); new_allocation.add_variable(new_variable); } } } private add_allocation(allocation: TextureAllocation) { this._allocations.push(allocation); } next_allocation_name(): ShaderName { const name = ParticleShaderNames[this._next_allocation_index]; this._next_allocation_index += 1; return name; } shader_names(): ShaderName[] { const explicit_shader_names = this._allocations.map((a) => a.shader_name); // include dependencies if needed // TODO: typescript - do I need those? // if (lodash_includes(explicit_shader_names, 'acceleration')) { // explicit_shader_names.push('velocity'); // } // if (lodash_includes(explicit_shader_names, 'velocity')) { // explicit_shader_names.push('position'); // } return ArrayUtils.uniq(explicit_shader_names); } create_shader_configs(): ShaderConfig[] { return [ // new ShaderConfig('position', ['position'], []), // new ShaderConfig('fragment', ['color', 'alpha'], ['vertex']), ]; } allocation_for_shader_name(shader_name: ShaderName): TextureAllocation { return this._allocations.filter((a) => a.shader_name == shader_name)[0]; } input_names_for_shader_name(root_node: BaseGlNodeType, shader_name: ShaderName) { const allocation = this.allocation_for_shader_name(shader_name); if (allocation) { return allocation.input_names_for_node(root_node); } } // find_variable(root_node: BaseNodeGl, shader_name: ShaderName, input_name: string): TextureVariable{ // const allocation = this.allocation_for_shader_name(shader_name) // if(allocation){ // return allocation.find_variable_with_node(root_node, input_name) // } // } variable(variable_name: string): TextureVariable | undefined { for (let allocation of this._allocations) { const variable = allocation.variable(variable_name); if (variable) { return variable; } } } variables(): TextureVariable[] { return this._allocations.map((a) => a.variables || []).flat(); } has_variable(name: string): boolean { const names = this.variables().map((v) => v.name()); return names.includes(name); } // allocation_for_variable(name:string):TextureAllocation{ // for(let allocation of this._allocations){ // const variables = allocation.variables() // for(let variable of variables){ // if(variable.name() == name){ // return allocation // } // } // } // } static from_json(data: TextureAllocationsControllerData): TextureAllocationsController { const controller = new TextureAllocationsController(); for (let datum of data) { const shader_name = Object.keys(datum)[0] as ShaderName; const allocation_data = datum[shader_name]; const new_allocation = TextureAllocation.from_json(allocation_data, shader_name); controller.add_allocation(new_allocation); } return controller; } toJSON(scene: PolyScene): TextureAllocationsControllerData { return this._allocations.map((allocation: TextureAllocation) => { const data = { [allocation.shader_name]: allocation.toJSON(scene), }; return data; }); } print(scene: PolyScene) { console.log(JSON.stringify(this.toJSON(scene), [''], 2)); } }