UNPKG

polygonjs-engine

Version:

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

185 lines (163 loc) 5.12 kB
import {BaseSopOperation} from './_Base'; import {DefaultOperationParams} from '../_Base'; import {CoreGroup} from '../../geometry/Group'; import {Object3D} from 'three/src/core/Object3D'; import {Group} from 'three/src/objects/Group'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; import {TypeAssert} from '../../../engine/poly/Assert'; interface HierarchySopParams extends DefaultOperationParams { mode: number; levels: number; objectMask: string; debugObjectMask: boolean; } export enum HierarchyMode { ADD_PARENT = 'add_parent', REMOVE_PARENT = 'remove_parent', ADD_CHILD = 'add_child', } export const HIERARCHY_MODES: Array<HierarchyMode> = [ HierarchyMode.ADD_PARENT, HierarchyMode.REMOVE_PARENT, HierarchyMode.ADD_CHILD, ]; export class HierarchySopOperation extends BaseSopOperation { static readonly DEFAULT_PARAMS: HierarchySopParams = { mode: 0, levels: 1, objectMask: '', debugObjectMask: false, }; static readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE; static type(): Readonly<'hierarchy'> { return 'hierarchy'; } cook(input_contents: CoreGroup[], params: HierarchySopParams) { const core_group = input_contents[0]; const mode = HIERARCHY_MODES[params.mode]; switch (mode) { case HierarchyMode.ADD_PARENT: { const objects = this._add_parent_to_core_group(core_group, params); return this.create_core_group_from_objects(objects); } case HierarchyMode.REMOVE_PARENT: { const objects = this._remove_parent_from_core_group(core_group, params); return this.create_core_group_from_objects(objects); } case HierarchyMode.ADD_CHILD: { const objects = this._add_child_to_core_group(core_group, input_contents[1], params); return this.create_core_group_from_objects(objects); } } TypeAssert.unreachable(mode); } // // // ADD PARENT // // private _add_parent_to_core_group(core_group: CoreGroup, params: HierarchySopParams): THREE.Object3D[] { if (params.levels == 0) { return core_group.objects(); } else { const new_object = this._add_parent_to_object(core_group.objects(), params); return [new_object]; } } private _add_parent_to_object(objects: THREE.Object3D[], params: HierarchySopParams): THREE.Object3D { let new_parent = new Group(); new_parent.matrixAutoUpdate = false; new_parent.add(...objects); if (params.levels > 0) { for (let i = 0; i < params.levels - 1; i++) { new_parent = this._add_new_parent(new_parent, params); } } return new_parent; } private _add_new_parent(object: THREE.Object3D, params: HierarchySopParams): THREE.Group { const new_parent2 = new Group(); new_parent2.matrixAutoUpdate = false; new_parent2.add(object); return new_parent2; } // // // REMOVE PARENT // // private _remove_parent_from_core_group(core_group: CoreGroup, params: HierarchySopParams): THREE.Object3D[] { if (params.levels == 0) { return core_group.objects(); } else { const new_objects: Object3D[] = []; for (let object of core_group.objects()) { const new_children = this._remove_parent_from_object(object, params); for (let new_child of new_children) { new_objects.push(new_child); } } return new_objects; } } private _remove_parent_from_object(object: THREE.Object3D, params: HierarchySopParams): THREE.Object3D[] { let current_children = object.children; for (let i = 0; i < params.levels - 1; i++) { current_children = this._get_children_from_objects(current_children, params); } return current_children; } private _get_children_from_objects(objects: THREE.Object3D[], params: HierarchySopParams): THREE.Object3D[] { let object; const children: Object3D[] = []; while ((object = objects.pop())) { if (object.children) { for (let child of object.children) { children.push(child); } } } return children; } // // // ADD CHILD // // private _add_child_to_core_group( core_group: CoreGroup, child_core_group: CoreGroup | undefined, params: HierarchySopParams ): THREE.Object3D[] { const objects = core_group.objects(); if (!child_core_group) { this.states?.error.set('input 1 is invalid'); return []; } const childObjects = child_core_group.objects(); const mask = params.objectMask.trim(); const maskValid = mask != ''; const parentObjects = maskValid ? this._findObjectsByMaskFromObjects(mask, objects) : objects; if (params.debugObjectMask) { console.log(parentObjects); } for (let i = 0; i < parentObjects.length; i++) { const parentObject = parentObjects[i]; // if there is no mask, we use the objects directly under the coreGroup const childObject = childObjects[i] || childObjects[0]; if (!childObject) { this.states?.error.set('no objects found in input 1'); return []; } parentObject.add(childObject); } return objects; } private _findObjectsByMaskFromObjects(mask: string, objects: Object3D[]) { const list: Object3D[] = []; for (let object of objects) { this.scene.objectsController.objectsByMaskInObject(mask, object, list); } return list; } }