import { Object3D, Group, Vector3, Quaternion } from '../../node_modules/three/build/three.module.js';
import { Reporter } from '../reporter/reporter.js';
import { InformationSource } from '../reporter/information_source.js';
import { BuildableComponent } from '../package/component/buildable_component.js';
import { StateTracker } from '../state_tracker.js';
import { Project } from '../project.js';
/**
* Actor
* @event Actor#bodychange emitted whenever the body changes, i.e. when a configuration is changed (but not when an element is dragged or rotated)
*/
class Actor extends StateTracker {
/**
* @param {Reporter} reporter
* @param {Object} settings
*/
constructor(reporter, settings) {
super(reporter, settings);
this.addEvent('bodychange');
this.hiddenBody = new Group();
this.body = new Group();
this.body.name = "Actor"
this.body.userData.origin = this;
this.body.castShadow = true;
this.body.receiveShadow = true;
this.visible = true;
}
/** @type {Boolean} */
visible;
show() {
console.log('show', this.label)
// while (this.body.children.length > 0) {
// this.body.add(this.hiddenBody.children[0]);
// }
this.body.traverse( function( child ) { child.layers.set( Project.layerMap.visibleActors ) } )
this.visible = true;
}
hide() {
console.log('hide', this.label)
// while (this.body.children.length > 0) {
// this.hiddenBody.add(this.body.children[0]);
// }
this.body.traverse( function( child ) { child.layers.set( Project.layerMap.hiddenActors ) } )
this.visible = false;
}
/**
* Removes all children from the body Group and disposes their
* Three.js resources (geometries, materials, textures) to prevent
* GPU memory leaks.
*/
clearBody() {
while (this.body.children.length > 0) {
const child = this.body.children[0];
this.body.remove(child);
// Dispose Three.js resources recursively
if (child.traverse) {
child.traverse(node => {
if (node.geometry && node.geometry.dispose) {
node.geometry.dispose();
}
if (node.material) {
if (Array.isArray(node.material)) {
node.material.forEach(m => { if (m.dispose) m.dispose(); });
} else if (node.material.dispose) {
node.material.dispose();
}
}
if (node.dispose && node !== child) {
node.dispose();
}
});
}
// Dispose the child itself
if (child.dispose) {
child.dispose();
}
}
// Also clean up hiddenBody
while (this.hiddenBody.children.length > 0) {
const child = this.hiddenBody.children[0];
this.hiddenBody.remove(child);
if (child.traverse) {
child.traverse(node => {
if (node.geometry && node.geometry.dispose) node.geometry.dispose();
if (node.material) {
if (Array.isArray(node.material)) {
node.material.forEach(m => { if (m.dispose) m.dispose(); });
} else if (node.material.dispose) {
node.material.dispose();
}
}
});
}
if (child.dispose) child.dispose();
}
}
/**
* @param {Object3D} newContent
*/
async updateBody(newContent, quaternion, position, modTransform) {
this.clearBody()
this.body.add(newContent);
if ( quaternion ) {
this.body.quaternion.copy( quaternion );
}
if ( position) {
if (modTransform && modTransform.translation) {
this.body.position.copy( new Vector3().addVectors( position, modTransform.translation ));
}
else {
this.body.position.copy( position );
}
}
await this.emit('bodychange', this.body);
}
destroy() {
this.clearBody();
if ( typeof super.destroy === 'function' ) {
super.destroy()
}
}
/** @type {Group} */
body = new Group();
}
export { Actor };