@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
121 lines (120 loc) • 4.11 kB
JavaScript
;
import { BaseSopOperation } from "./_Base";
import { Group } from "three";
import { pushOnArrayAtEntry, addToSetAtEntry } from "../../../core/MapUtils";
import { InputCloneMode } from "../../../engine/poly/InputCloneMode";
import { isBooleanTrue } from "../../../core/BooleanValue";
import { coreObjectClassFactory } from "../../../core/geometry/CoreObjectFactory";
import { setToArray } from "../../../core/SetUtils";
const _MergeSopOperation = class extends BaseSopOperation {
static type() {
return "merge";
}
// TODO: improvement:
// for compact, I should really keep track of geometry ids,
// to make sure I am not including a geometry twice, if there is a hierarchy
cook(inputCoreGroups, params) {
var _a;
let allObjects = [];
for (const inputCoreGroup of inputCoreGroups) {
if (inputCoreGroup) {
const objects = inputCoreGroup.allObjects();
if (isBooleanTrue(params.compact)) {
for (const object of objects) {
object.traverse((child) => {
allObjects.push(child);
});
}
} else {
for (const object of objects) {
allObjects.push(object);
}
}
}
}
if (isBooleanTrue(params.compact)) {
allObjects = _MergeSopOperation.makeCompact(allObjects, params, (_a = this.states) == null ? void 0 : _a.error);
}
return this.createCoreGroupFromObjects(allObjects);
}
static makeCompact(allObjects, options, errorState) {
const { preserveMaterials } = options;
const materialsByObjectType = /* @__PURE__ */ new Map();
const objectsByType = /* @__PURE__ */ new Map();
const orderedObjectTypes = [];
for (let object of allObjects) {
object.traverse((object3d) => {
if (object3d instanceof Group) {
return;
}
const objectType = object.type;
if (objectType) {
if (!orderedObjectTypes.includes(objectType)) {
orderedObjectTypes.push(objectType);
}
if (objectType) {
const foundMat = materialsByObjectType.get(objectType);
if (!foundMat) {
materialsByObjectType.set(objectType, object.material);
}
pushOnArrayAtEntry(objectsByType, objectType, object);
}
}
});
}
const mergedObjects = [];
orderedObjectTypes.forEach((objectType) => {
const material = materialsByObjectType.get(objectType);
const objects = objectsByType.get(objectType);
if (objects && objects.length != 0) {
if (isBooleanTrue(preserveMaterials)) {
_makeCompactWithPreservedMaterials({
objects,
material,
objectType,
mergedObjects,
onError: (message) => {
errorState == null ? void 0 : errorState.set(message);
}
});
} else {
const coreObjectClass = coreObjectClassFactory(objects[0]);
coreObjectClass.mergeCompact({
objects,
material,
objectType,
mergedObjects,
onError: (message) => {
errorState == null ? void 0 : errorState.set(message);
}
});
}
}
});
return mergedObjects;
}
};
export let MergeSopOperation = _MergeSopOperation;
MergeSopOperation.DEFAULT_PARAMS = {
compact: false,
preserveMaterials: true
};
MergeSopOperation.INPUT_CLONED_STATE = InputCloneMode.FROM_NODE;
const objectsByMaterial = /* @__PURE__ */ new Map();
function _makeCompactWithPreservedMaterials(options) {
const { objects, objectType, mergedObjects, onError } = options;
const coreObjectClass = coreObjectClassFactory(objects[0]);
objectsByMaterial.clear();
for (let object of objects) {
addToSetAtEntry(objectsByMaterial, object.material, object);
}
objectsByMaterial.forEach((objectSet, material) => {
coreObjectClass.mergeCompact({
objects: setToArray(objectSet, []),
material,
objectType,
mergedObjects,
onError
});
});
}