@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
194 lines (175 loc) • 5.65 kB
text/typescript
import {ObjectNamedFunction3} from './_Base';
import {_matchArrayLength} from './_ArrayUtils';
import {Object3D} from 'three';
import {JsDataType} from '../nodes/utils/io/connections/Js';
import {Ref} from '@vue/reactivity';
import {isVector, isColor, isBoolean, isNumber, isString, isArray, isQuaternion} from '../../core/Type';
import {ref} from '../../core/reactivity/CoreReactivity';
import {PolyScene} from '../scene/PolyScene';
export interface ActorEvaluatorDebugOptions {
object3D: Object3D;
nodePath: string;
message: string;
value: JsDataType;
}
export interface DebugLine {
objectName: string;
value: JsDataType;
displayableValue: string;
}
const options: ActorEvaluatorDebugOptions = {
object3D: new Object3D(),
nodePath: '',
message: '',
value: 0,
};
interface DebugDataController {
lastProcessedFrameByNodePath: Map<string, number>;
debugContentByFrameByNodePath: Ref<Record<string, DebugLine[]>>;
// arrayByNodePath: Map<string, Array<DebugLine>>;
}
const _debugDataController: DebugDataController = {
lastProcessedFrameByNodePath: new Map(),
debugContentByFrameByNodePath: ref({}),
// arrayByNodePath: new Map(),
};
// function _getarrayByNodePath(nodePath: string, controller: DebugDataController) {
// let array = controller.arrayByNodePath.get(nodePath);
// if (!array) {
// array = [];
// controller.arrayByNodePath.set(nodePath, array);
// }
// return array;
// }
function _displayableValue(value: JsDataType): string {
try {
if (isBoolean(value) || isString(value)) {
return `${value}`;
}
if (isNumber(value)) {
return `${value.toFixed(6)}`;
}
if (isColor(value)) {
return value
.toArray()
.map((e) => e.toFixed(4))
.join(', ');
}
if (isVector(value) || isQuaternion(value)) {
return value
.toArray()
.map((e) => e.toFixed(4))
.join(', ');
}
if (isArray(value)) {
const firstElement = value[0];
const firstElementAsString = _displayableValue(firstElement);
return `[${firstElementAsString},...] (length: ${value.length})`;
}
return 'value not displayabled, see dev console';
} catch (err) {
console.warn('error trying to display value:', value);
return '';
}
}
export function tableContent(debugLines: DebugLine[]) {
const entries = debugLines.map((debugLine, i) => {
return {
objectName: debugLine.objectName,
value: isVector(debugLine.value) || isColor(debugLine.value) ? debugLine.value.toArray() : debugLine.value,
};
});
return entries;
}
function logBlue(message: string) {
console.log('%c' + message, 'color:blue; font-weight:bold;');
}
function _flushDebugNode(nodePath: string, debugLines: DebugLine[]) {
logBlue('------------');
console.log(`${nodePath}:`);
console.table(tableContent(debugLines));
logBlue('------------');
}
function optionsToDebugLines(
scene: PolyScene,
options: ActorEvaluatorDebugOptions,
debugDataController: DebugDataController
) {
const {object3D, nodePath, value} = options;
const displayableValue = _displayableValue(value);
const objectName = object3D.name || 'no name';
const currentFrame = scene.frame();
let currentValue = debugDataController.debugContentByFrameByNodePath.value[nodePath];
if (!currentValue) {
currentValue = []; //_getarrayByNodePath(nodePath, debugDataController);
// currentValue.length = 0;
debugDataController.debugContentByFrameByNodePath.value[nodePath] = currentValue;
}
currentValue.push({
objectName,
value,
displayableValue,
});
// console.log({options, displayableValue, objectName, currentValue, currentFrame});
const cachedProcessedFrame = debugDataController.lastProcessedFrameByNodePath.get(nodePath);
const lastProcessedFrame = cachedProcessedFrame != null ? cachedProcessedFrame : -1;
if (!lastProcessedFrame) {
debugDataController.lastProcessedFrameByNodePath.set(nodePath, lastProcessedFrame);
}
if (currentFrame != lastProcessedFrame) {
// flush for current node
_flushDebugNode(nodePath, currentValue);
if (scene.dispatchController.emitAllowed()) {
scene.dispatchController.actorEvaluatorDebug({nodePath, debugLines: currentValue});
}
currentValue.length = 0;
debugDataController.lastProcessedFrameByNodePath.set(nodePath, currentFrame);
}
return currentValue;
}
function _optionsToDebugLines(scene: PolyScene, options: ActorEvaluatorDebugOptions) {
return optionsToDebugLines(scene, options, _debugDataController);
}
export interface DebugOptions {
displayValue: boolean;
displayFrame: boolean;
displayTime: boolean;
displayNodePath: boolean;
message: string;
bundleByObject: boolean;
}
export class debug<T extends JsDataType> extends ObjectNamedFunction3<[string, T, DebugOptions]> {
static override type() {
return 'debug';
}
override func(object3D: Object3D, nodePath: string, input: T, debugOptions: DebugOptions): T {
const messageElements: any[] = [];
if (debugOptions.displayFrame) {
messageElements.push(`${this.scene.frame()}`);
}
if (debugOptions.displayTime) {
messageElements.push(`${this.scene.time()}`);
}
if (debugOptions.message) {
messageElements.push(debugOptions.message);
}
if (debugOptions.displayNodePath) {
messageElements.push(nodePath);
}
const message = messageElements.join(' ');
if (debugOptions.bundleByObject) {
options.object3D = object3D;
// this must remain nodePath, for the debug extra UI to work
options.nodePath = nodePath;
options.message = message;
options.value = input;
_optionsToDebugLines(this.scene, options);
} else {
if (debugOptions.displayValue) {
messageElements.push(input);
}
console.log(...messageElements);
}
return input;
}
}