polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
198 lines (197 loc) • 8.05 kB
JavaScript
import {MapUtils as MapUtils2} from "../../../../../core/MapUtils";
import {GLDefinitionType} from "../../utils/GLDefinition";
import {TypedGLDefinitionCollection} from "../../utils/GLDefinitionCollection";
import {ParamConfigsController as ParamConfigsController2} from "../../../../nodes/utils/code/controllers/ParamConfigsController";
import {ShadersCollectionController as ShadersCollectionController2} from "./ShadersCollectionController";
import {CodeFormatter as CodeFormatter2} from "./CodeFormatter";
import {LineType as LineType2} from "./LineType";
import {ArrayUtils as ArrayUtils2} from "../../../../../core/ArrayUtils";
export class CodeBuilder {
constructor(_node_traverser, _root_nodes_for_shader_method) {
this._node_traverser = _node_traverser;
this._root_nodes_for_shader_method = _root_nodes_for_shader_method;
this._param_configs_controller = new ParamConfigsController2();
this._param_configs_set_allowed = true;
this._lines = new Map();
}
shader_names() {
return this._node_traverser.shader_names();
}
build_from_nodes(root_nodes, param_nodes) {
this._node_traverser.traverse(root_nodes);
const nodes_by_shader_name = new Map();
for (let shader_name of this.shader_names()) {
const nodes = this._node_traverser.nodes_for_shader_name(shader_name);
nodes_by_shader_name.set(shader_name, nodes);
}
const sorted_nodes = this._node_traverser.sorted_nodes();
for (let shader_name of this.shader_names()) {
const root_nodes_for_shader = this._root_nodes_for_shader_method(shader_name);
for (let root_node of root_nodes_for_shader) {
MapUtils2.push_on_array_at_entry(nodes_by_shader_name, shader_name, root_node);
}
}
const sorted_node_ids = new Map();
for (let node of sorted_nodes) {
sorted_node_ids.set(node.graphNodeId(), true);
}
for (let root_node of root_nodes) {
if (!sorted_node_ids.get(root_node.graphNodeId())) {
sorted_nodes.push(root_node);
sorted_node_ids.set(root_node.graphNodeId(), true);
}
}
for (let node of sorted_nodes) {
node.reset_code();
}
for (let node of param_nodes) {
node.reset_code();
}
this._shaders_collection_controller = new ShadersCollectionController2(this.shader_names(), this.shader_names()[0]);
this.reset();
for (let shader_name of this.shader_names()) {
let nodes = nodes_by_shader_name.get(shader_name) || [];
nodes = ArrayUtils2.uniq(nodes);
this._shaders_collection_controller.set_current_shader_name(shader_name);
if (nodes) {
for (let node of nodes) {
node.set_lines(this._shaders_collection_controller);
}
}
}
if (this._param_configs_set_allowed) {
for (let param_node of param_nodes) {
param_node.set_param_configs();
}
this.set_param_configs(param_nodes);
}
this.set_code_lines(sorted_nodes);
}
shaders_collection_controller() {
return this._shaders_collection_controller;
}
disallow_new_param_configs() {
this._param_configs_set_allowed = false;
}
allow_new_param_configs() {
this._param_configs_set_allowed = true;
}
reset() {
for (let shader_name of this.shader_names()) {
const lines_map = new Map();
this._lines.set(shader_name, lines_map);
}
}
param_configs() {
return this._param_configs_controller.list || [];
}
lines(shader_name, line_type) {
return this._lines.get(shader_name)?.get(line_type) || [];
}
all_lines() {
return this._lines;
}
set_param_configs(nodes) {
this._param_configs_controller.reset();
for (let node of nodes) {
const param_configs = node.param_configs();
if (param_configs) {
for (let param_config of param_configs) {
this._param_configs_controller.push(param_config);
}
}
}
}
set_code_lines(nodes) {
for (let shader_name of this.shader_names()) {
this.add_code_lines(nodes, shader_name);
}
}
add_code_lines(nodes, shader_name) {
this.add_definitions(nodes, shader_name, GLDefinitionType.FUNCTION, LineType2.FUNCTION_DECLARATION);
this.add_definitions(nodes, shader_name, GLDefinitionType.UNIFORM, LineType2.DEFINE);
this.add_definitions(nodes, shader_name, GLDefinitionType.VARYING, LineType2.DEFINE);
this.add_definitions(nodes, shader_name, GLDefinitionType.ATTRIBUTE, LineType2.DEFINE);
this.add_code_line_for_nodes_and_line_type(nodes, shader_name, LineType2.BODY);
}
add_definitions(nodes, shader_name, definition_type, line_type) {
if (!this._shaders_collection_controller) {
return;
}
const definitions = [];
for (let node of nodes) {
let node_definitions = this._shaders_collection_controller.definitions(shader_name, node);
if (node_definitions) {
node_definitions = node_definitions.filter((d) => d.definition_type == definition_type);
for (let definition of node_definitions) {
definitions.push(definition);
}
}
}
if (definitions.length > 0) {
const collection = new TypedGLDefinitionCollection(definitions);
const uniq_definitions = collection.uniq();
if (collection.errored) {
throw `code builder error: ${collection.error_message}`;
}
const definitions_by_node_id = new Map();
const node_ids = new Map();
for (let definition of uniq_definitions) {
const node_id = definition.node.graphNodeId();
if (!node_ids.has(node_id)) {
node_ids.set(node_id, true);
}
MapUtils2.push_on_array_at_entry(definitions_by_node_id, node_id, definition);
}
const lines_for_shader = this._lines.get(shader_name);
node_ids.forEach((_, node_id) => {
const definitions2 = definitions_by_node_id.get(node_id);
if (definitions2) {
const first_definition = definitions2[0];
if (first_definition) {
const comment = CodeFormatter2.node_comment(first_definition.node, line_type);
MapUtils2.push_on_array_at_entry(lines_for_shader, line_type, comment);
for (let definition of definitions2) {
const line = CodeFormatter2.line_wrap(first_definition.node, definition.line, line_type);
MapUtils2.push_on_array_at_entry(lines_for_shader, line_type, line);
}
const separator = CodeFormatter2.post_line_separator(line_type);
MapUtils2.push_on_array_at_entry(lines_for_shader, line_type, separator);
}
}
});
}
}
add_code_line_for_nodes_and_line_type(nodes, shader_name, line_type) {
nodes = nodes.filter((node) => {
if (this._shaders_collection_controller) {
const lines = this._shaders_collection_controller.body_lines(shader_name, node);
return lines && lines.length > 0;
}
});
var nodes_count = nodes.length;
for (let i = 0; i < nodes_count; i++) {
const is_last = i == nodes.length - 1;
this.add_code_line_for_node_and_line_type(nodes[i], shader_name, line_type, is_last);
}
}
add_code_line_for_node_and_line_type(node, shader_name, line_type, is_last) {
if (!this._shaders_collection_controller) {
return;
}
const lines = this._shaders_collection_controller.body_lines(shader_name, node);
if (lines && lines.length > 0) {
const lines_for_shader = this._lines.get(shader_name);
const comment = CodeFormatter2.node_comment(node, line_type);
MapUtils2.push_on_array_at_entry(lines_for_shader, line_type, comment);
ArrayUtils2.uniq(lines).forEach((line) => {
line = CodeFormatter2.line_wrap(node, line, line_type);
MapUtils2.push_on_array_at_entry(lines_for_shader, line_type, line);
});
if (!(line_type == LineType2.BODY && is_last)) {
const separator = CodeFormatter2.post_line_separator(line_type);
MapUtils2.push_on_array_at_entry(lines_for_shader, line_type, separator);
}
}
}
}