polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
346 lines (314 loc) • 12.2 kB
text/typescript
import {PolyScene} from '../scene/PolyScene';
import {CoreGraphNode} from '../../core/graph/CoreGraphNode';
import {UIData} from './utils/UIData';
import {FlagsController, FlagsControllerD} from './utils/FlagsController';
import {StatesController} from './utils/StatesController';
import {HierarchyParentController} from './utils/hierarchy/ParentController';
import {HierarchyChildrenController} from './utils/hierarchy/ChildrenController';
import {LifeCycleController} from './utils/LifeCycleController';
import {TypedContainerController} from './utils/ContainerController';
import {NodeCookController} from './utils/CookController';
import {NameController} from './utils/NameController';
import {NodeSerializer, NodeSerializerData} from './utils/Serializer';
import {ParamsController} from './utils/params/ParamsController';
import {ParamConstructorMap} from '../params/types/ParamConstructorMap';
import {ParamInitValuesTypeMap} from '../params/types/ParamInitValuesTypeMap';
import {NodeParamsConfig} from './utils/params/ParamsConfig';
import {ParamsValueAccessor, ParamsValueAccessorType} from './utils/params/ParamsValueAccessor';
// import {ProcessingContext} from './utils/ProcessingContext';
import {IOController, ParamsInitData} from './utils/io/IOController';
import {NodeEvent} from '../poly/NodeEvent';
import {NodeContext} from '../poly/NodeContext';
import {ParamsAccessorType, ParamsAccessor} from './utils/params/ParamsAccessor';
export interface NodeDeletedEmitData {
parent_id: CoreGraphNodeId;
}
export interface NodeCreatedEmitData {
child_node_json: NodeSerializerData;
}
type EmitDataByNodeEventMapGeneric = {[key in NodeEvent]: any};
export interface EmitDataByNodeEventMap extends EmitDataByNodeEventMapGeneric {
[NodeEvent.CREATED]: NodeCreatedEmitData;
[NodeEvent.DELETED]: NodeDeletedEmitData;
[NodeEvent.ERROR_UPDATED]: undefined;
}
export interface IntegrationData {
name: string;
data: PolyDictionary<string>;
}
// import {ContainerMap, ContainerType} from '../containers/utils/ContainerMap';
import {ContainableMap} from '../containers/utils/ContainableMap';
import {ParamOptions} from '../params/utils/OptionsController';
import {ParamType} from '../poly/ParamType';
import {DisplayNodeController} from './utils/DisplayNodeController';
import {NodeTypeMap} from '../containers/utils/ContainerMap';
import {ParamInitValueSerialized} from '../params/types/ParamInitValueSerialized';
import {ModuleName} from '../poly/registers/modules/_BaseRegister';
import {BasePersistedConfig} from './utils/PersistedConfig';
import {AssemblerName} from '../poly/registers/assemblers/_BaseRegister';
import {PolyNodeController} from './utils/poly/PolyNodeController';
import {CoreGraphNodeId} from '../../core/graph/CoreGraph';
import {PolyDictionary} from '../../types/GlobalTypes';
export class TypedNode<NC extends NodeContext, K extends NodeParamsConfig> extends CoreGraphNode {
container_controller: TypedContainerController<NC> = new TypedContainerController<NC>(this);
private _parent_controller: HierarchyParentController | undefined;
private _ui_data: UIData | undefined;
private _states: StatesController | undefined;
private _lifecycle: LifeCycleController | undefined;
private _serializer: NodeSerializer | undefined;
private _cook_controller: NodeCookController<NC> | undefined;
public readonly flags: FlagsController | undefined;
public readonly display_node_controller: DisplayNodeController | undefined;
public readonly persisted_config: BasePersistedConfig | undefined;
private _params_controller: ParamsController | undefined;
readonly params_config: K | undefined;
readonly pv: ParamsValueAccessorType<K> = (<unknown>new ParamsValueAccessor<K>()) as ParamsValueAccessorType<K>;
// readonly pv: ParamsValueAccessor<K> = new ParamsValueAccessor<K>(this);
readonly p: ParamsAccessorType<K> = (<unknown>new ParamsAccessor<K>()) as ParamsAccessorType<K>;
copy_param_values(node: TypedNode<NC, K>) {
const non_spare = this.params.non_spare;
for (let param of non_spare) {
const other_param = node.params.get(param.name());
if (other_param) {
param.copy_value(other_param);
}
}
}
private _name_controller: NameController | undefined;
get parentController(): HierarchyParentController {
return (this._parent_controller = this._parent_controller || new HierarchyParentController(this));
}
static displayedInputNames(): string[] {
return [];
}
private _children_controller: HierarchyChildrenController | undefined;
protected _children_controller_context: NodeContext | undefined;
get childrenControllerContext() {
return this._children_controller_context;
}
private _create_children_controller(): HierarchyChildrenController | undefined {
if (this._children_controller_context) {
return new HierarchyChildrenController(this, this._children_controller_context);
}
}
get childrenController(): HierarchyChildrenController | undefined {
return (this._children_controller = this._children_controller || this._create_children_controller());
}
childrenAllowed(): boolean {
return this._children_controller_context != null;
}
get uiData(): UIData {
return (this._ui_data = this._ui_data || new UIData(this));
}
get states(): StatesController {
return (this._states = this._states || new StatesController(this));
}
get lifecycle(): LifeCycleController {
return (this._lifecycle = this._lifecycle || new LifeCycleController(this));
}
get serializer(): NodeSerializer {
return (this._serializer = this._serializer || new NodeSerializer(this));
}
get cookController(): NodeCookController<NC> {
return (this._cook_controller = this._cook_controller || new NodeCookController(this));
}
protected _io: IOController<NC> | undefined;
get io(): IOController<NC> {
return (this._io = this._io || new IOController(this));
}
get nameController(): NameController {
return (this._name_controller = this._name_controller || new NameController(this));
}
setName(name: string) {
this.nameController.setName(name);
}
_set_core_name(name: string) {
this._name = name;
}
get params(): ParamsController {
return (this._params_controller = this._params_controller || new ParamsController(this));
}
// get processing_context(): ProcessingContext {
// return (this._processing_context = this._processing_context || new ProcessingContext(this));
// }
constructor(scene: PolyScene, name: string = 'BaseNode', public params_init_value_overrides?: ParamsInitData) {
super(scene, name);
}
private _initialized: boolean = false;
public initialize_base_and_node() {
if (!this._initialized) {
this._initialized = true;
this.display_node_controller?.initializeNode();
this.initializeBaseNode(); // for base classes of Sop, Obj...
this.initializeNode(); // for Derivated node clases, like BoxSop, TransformSop...
if (this.polyNodeController) {
this.polyNodeController.initializeNode();
}
} else {
console.warn('node already initialized');
}
}
protected initializeBaseNode() {}
protected initializeNode() {}
static type(): string {
throw 'type to be overriden';
}
type() {
const c = this.constructor as typeof BaseNodeClass;
return c.type();
}
static nodeContext(): NodeContext {
console.error('node has no node_context', this);
throw 'node_context requires override';
}
nodeContext(): NodeContext {
const c = this.constructor as typeof BaseNodeClass;
return c.nodeContext();
}
static require_webgl2(): boolean {
return false;
}
require_webgl2(): boolean {
const c = this.constructor as typeof BaseNodeClass;
return c.require_webgl2();
}
setParent(parent: BaseNodeType | null) {
this.parentController.setParent(parent);
}
parent() {
return this.parentController.parent();
}
root() {
return this._scene.root();
}
fullPath(relative_to_parent?: BaseNodeType): string {
return this.parentController.fullPath(relative_to_parent);
}
// params
create_params() {}
addParam<T extends ParamType>(
type: T,
name: string,
default_value: ParamInitValuesTypeMap[T],
options?: ParamOptions
): ParamConstructorMap[T] | undefined {
return this._params_controller?.addParam(type, name, default_value, options);
}
param_default_value(name: string): ParamInitValueSerialized {
return null;
}
// cook
cook(input_contents: any[]): any {
return null;
}
// container
async requestContainer() {
if (!this.isDirty()) {
return this.container_controller.container;
} else {
return await this.container_controller.requestContainer();
}
}
setContainer(content: ContainableMap[NC], message: string | null = null) {
// TODO: typescript: why is this a type of never
this.container_controller.container.set_content(content as never); //, this.self.cook_eval_key());
if (content != null) {
if (!(content as any).name) {
(content as any).name = this.fullPath();
}
if (!(content as any).node) {
(content as any).node = this;
}
}
this.cookController.end_cook(message);
}
// hierarchy
createNode(node_class: any, params_init_value_overrides?: ParamsInitData) {
return this.childrenController?.createNode(node_class, params_init_value_overrides);
}
create_operation_container(
type: string,
operation_container_name: string,
params_init_value_overrides?: ParamsInitData
) {
return this.childrenController?.create_operation_container(
type,
operation_container_name,
params_init_value_overrides
);
}
removeNode(node: BaseNodeType) {
this.childrenController?.removeNode(node);
}
dispose() {
super.dispose();
this.setParent(null);
this.io.inputs.dispose();
this.lifecycle.dispose();
this.display_node_controller?.dispose();
this.nameController.dispose();
this.childrenController?.dispose();
this.params.dispose();
}
children() {
return this.childrenController?.children() || [];
}
node(path: string) {
return this.parentController?.find_node(path) || null;
}
nodeSibbling(name: string): NodeTypeMap[NC] | null {
const parent = this.parent();
if (parent) {
const node = parent.childrenController?.child_by_name(name);
if (node) {
return node as NodeTypeMap[NC];
}
}
return null;
}
nodesByType(type: string) {
return this.childrenController?.nodesByType(type) || [];
}
// inputs
setInput(
input_index_or_name: number | string,
node: NodeTypeMap[NC] | null,
output_index_or_name: number | string = 0
) {
this.io.inputs.setInput(input_index_or_name, node, output_index_or_name);
}
// emit
emit(event_name: NodeEvent.CREATED, data: EmitDataByNodeEventMap[NodeEvent.CREATED]): void;
emit(event_name: NodeEvent.DELETED, data: EmitDataByNodeEventMap[NodeEvent.DELETED]): void;
emit(event_name: NodeEvent.NAME_UPDATED): void;
emit(event_name: NodeEvent.OVERRIDE_CLONABLE_STATE_UPDATE): void;
emit(event_name: NodeEvent.NAMED_INPUTS_UPDATED): void;
emit(event_name: NodeEvent.NAMED_OUTPUTS_UPDATED): void;
emit(event_name: NodeEvent.INPUTS_UPDATED): void;
emit(event_name: NodeEvent.PARAMS_UPDATED): void;
emit(event_name: NodeEvent.UI_DATA_POSITION_UPDATED): void;
emit(event_name: NodeEvent.UI_DATA_COMMENT_UPDATED): void;
emit(event_name: NodeEvent.ERROR_UPDATED): void;
emit(event_name: NodeEvent.FLAG_BYPASS_UPDATED): void;
emit(event_name: NodeEvent.FLAG_DISPLAY_UPDATED): void;
emit(event_name: NodeEvent.FLAG_OPTIMIZE_UPDATED): void;
emit(event_name: NodeEvent.SELECTION_UPDATED): void;
emit(event_name: NodeEvent, data: object | null = null): void {
this.scene().dispatchController.dispatch(this, event_name, data);
}
// serializer
toJSON(include_param_components: boolean = false) {
return this.serializer.toJSON(include_param_components);
}
// modules
public async requiredModules(): Promise<ModuleName[] | void> {}
public usedAssembler(): AssemblerName | void {}
public integrationData(): IntegrationData | void {}
// poly nodes
public readonly polyNodeController: PolyNodeController | undefined;
}
export type BaseNodeType = TypedNode<any, any>;
export class BaseNodeClass extends TypedNode<any, any> {}
export class BaseNodeClassWithDisplayFlag extends TypedNode<any, any> {
public readonly flags: FlagsControllerD = new FlagsControllerD(this);
}