@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
231 lines (230 loc) • 8.37 kB
JavaScript
"use strict";
import { CoreFeaturesController } from "./../../../../../core/FeaturesController";
import { ParamConfig } from "../../../utils/params/ParamsConfig";
import { setToArray } from "../../../../../core/SetUtils";
import { Poly } from "../../../../Poly";
import { arrayUniq, arrayCompact, arrayToSet } from "../../../../../core/ArrayUtils";
class NodeGroup {
constructor(nodes) {
this.nodes = nodes;
this._remaining = /* @__PURE__ */ new Set();
if (CoreFeaturesController.debugLoadProgress()) {
console.log(nodes);
}
this.totalCount = nodes.length;
this._processed = /* @__PURE__ */ new Set();
arrayToSet(nodes, this._remaining);
}
markNodeAsProcessed(node) {
this._processed.add(node);
this._remaining.delete(node);
if (CoreFeaturesController.debugLoadProgress()) {
console.log("markNodeAsProcessed", node.path(), {
processed: setToArray(this._processed, []).map((n) => n.path()),
remaining: setToArray(this._remaining, []).map((n) => n.path())
});
}
}
isNodeProcessed(node) {
return this._processed.has(node);
}
processedCount() {
return this._processed.size;
}
}
export function RootLoadProgressParamConfig(Base) {
return class Mixin extends Base {
constructor() {
super(...arguments);
/** @param when the scene loads, nodes that match the mask will update the progress bar as they cook */
this.nodesMask = ParamConfig.STRING("*/image* */envMap*", {
cook: false,
separatorBefore: true,
objectMask: false
// do not use objectMask, since it is a node mask, not object
});
/** @param prints which nodes match the mask in the console */
this.printNodes = ParamConfig.BUTTON(null, {
cook: false,
callback: (node) => {
RootLoadProgressController.PARAM_CALLBACK_printResolve(node);
}
// objectMask: false // do not use objectMask, since it is a node mask, not object
});
}
};
}
export class RootLoadProgressController {
constructor(node) {
this.node = node;
}
static async PARAM_CALLBACK_printResolve(node) {
const nodes = await node.loadProgress.resolvedNodes();
console.log(nodes);
const nodePaths = nodes.map((node2) => node2.path()).sort();
console.log(nodePaths);
}
async resolvedNodes() {
const param = this.node.p.nodesMask;
if (param.isDirty()) {
await param.compute();
}
const mask = param.value;
const scene = this.node.scene();
const nodes = scene.nodesController.nodesFromMask(mask || "");
const nodeDisplayNodes = await this._loadDisplayNodes();
const uniqNodes = [];
arrayUniq(nodes.concat(nodeDisplayNodes), uniqNodes);
return uniqNodes;
}
async _loadDisplayNodes() {
const scene = this.node.scene();
const cameraNodeTypes = Poly.camerasRegister.registeredNodeTypes();
const cameraNodes = cameraNodeTypes.map((type) => scene.nodesByType(type)).flat();
const displayNodes = this._displayNodes();
const nodes = cameraNodes.concat(displayNodes);
const cameraCreatorNode = await this.cameraCreatorNode();
if (cameraCreatorNode) {
nodes.push(cameraCreatorNode);
}
const uniqNodes = [];
arrayUniq(nodes, uniqNodes);
return uniqNodes;
}
_displayNodes() {
const objNodesWithDisplayNodeController = this._objectNodesWithDisplayNodeController();
const displayNodes = [];
arrayCompact(
objNodesWithDisplayNodeController.map((node) => node.displayNodeController.firstNonBypassedDisplayNode()),
displayNodes
);
return displayNodes;
}
_objectNodesWithDisplayNodeController() {
const scene = this.node.scene();
const objNodesWithDisplayNodeController = scene.root().children().filter((node) => node.displayNodeController != null).filter((node) => {
var _a, _b;
return (_b = (_a = node.flags) == null ? void 0 : _a.display) == null ? void 0 : _b.active();
});
return objNodesWithDisplayNodeController;
}
// private _getNodesWithSopGroup() {
// return this._displayNodes().filter((node) => (node as GeoObjNode).childrenDisplayController != null);
// }
cameraCreatorNode() {
return this.node.mainCameraController.cameraCreatorNode();
}
_runCallback(progress, nodeTrigger) {
this._debug2("_runCallback", { progress, nodeTrigger });
if (!(this._onProgressUpdateCallback && this._nodeGroups)) {
return;
}
this._debug2("_onProgressUpdateCallback", this._nodeGroups);
this._onProgressUpdateCallback(progress, {
scene: this.node.scene(),
triggerNode: void 0,
groups: this._nodeGroups
});
}
_updateProgressAndRunCallback(nodeTrigger) {
if (!(this._onProgressUpdateCallback && this._nodeGroups)) {
return;
}
const totalNodesCount = this._nodeGroups.toCook.totalCount + this._nodeGroups.sopGroupToUpdate.totalCount;
const processedNodesCount = this._nodeGroups.toCook.processedCount() + this._nodeGroups.sopGroupToUpdate.processedCount();
const progress = processedNodesCount / totalNodesCount;
this._runCallback(progress, nodeTrigger);
}
async watchNodesProgress(callback) {
this._onProgressUpdateCallback = callback;
const resolvedNodes = await this.resolvedNodes();
const nodesToCook = resolvedNodes.filter((node) => node.isDirty());
this._debug({ nodesToCook });
const nodesToUpdateSopGroup = this._objectNodesWithDisplayNodeController().filter((node) => {
var _a;
const displayNode = node.displayNodeController.displayNode();
return displayNode != null && !((_a = displayNode.flags.bypass) == null ? void 0 : _a.active());
}).filter((node) => node.isDirty());
this._debug({ nodesToUpdateSopGroup });
this._nodeGroups = {
toCook: new NodeGroup(nodesToCook),
sopGroupToUpdate: new NodeGroup(nodesToUpdateSopGroup)
};
const totalNodesCount = this._nodeGroups.toCook.totalCount + this._nodeGroups.sopGroupToUpdate.totalCount;
this._debug({ totalNodesCount });
if (totalNodesCount == 0) {
this._runCallback(1);
return;
}
this._watchNodesWithSopGroup();
this._watchNodesToCook();
}
async _watchNodesToCook() {
var _a;
const nodesGroup = (_a = this._nodeGroups) == null ? void 0 : _a.toCook;
if (!nodesGroup) {
return;
}
const callbackName = "RootLoadProgressController";
const onNodeCooked = (node) => {
if (!nodesGroup.isNodeProcessed(node)) {
nodesGroup.markNodeAsProcessed(node);
this._updateProgressAndRunCallback(node);
node.cookController.deregisterOnCookEnd(callbackName);
}
};
for (const node of nodesGroup.nodes) {
node.cookController.registerOnCookEnd(callbackName, () => {
this._debug2("nodeToCook - completed", node.path());
onNodeCooked(node);
});
this._debug2("nodeToCook - start", node.path());
node.compute();
}
}
_watchNodesWithSopGroup() {
var _a;
const nodesGroup = (_a = this._nodeGroups) == null ? void 0 : _a.sopGroupToUpdate;
if (!nodesGroup) {
return;
}
const callbackName = "RootLoadProgressController";
const onNodeCooked = (node) => {
if (!nodesGroup.isNodeProcessed(node)) {
nodesGroup.markNodeAsProcessed(node);
this._updateProgressAndRunCallback(node);
const childrenDisplayController = node.childrenDisplayController;
childrenDisplayController.deregisterOnSopGroupUpdated(callbackName);
}
};
for (const node of nodesGroup.nodes) {
const childrenDisplayController = node.childrenDisplayController;
this._debug2("nodeWithSopGroup - watch", node.path());
childrenDisplayController.registerOnSopGroupUpdated(callbackName, () => {
this._debug2("nodeWithSopGroup - completed", node.path());
onNodeCooked(node);
});
}
}
static debugActive() {
return CoreFeaturesController.debugLoadProgress();
}
static debug(arg0) {
if (!this.debugActive()) {
return;
}
console.log(arg0);
}
static debug2(arg0, arg1) {
if (!this.debugActive()) {
return;
}
console.log(arg0, arg1);
}
_debug(arg0) {
RootLoadProgressController.debug(arg0);
}
_debug2(arg0, arg1) {
RootLoadProgressController.debug2(arg0, arg1);
}
}