polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
185 lines (163 loc) • 5.12 kB
text/typescript
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;
}
}