feat(All):Initial

This commit is contained in:
2025-10-04 23:36:07 +08:00
commit 2b4e5d2668
1321 changed files with 415958 additions and 0 deletions
@@ -0,0 +1,49 @@
import { Command } from './Command';
import { ObjectLoader } from '../loader/ObjectLoader';
import App from "../app/App";
/**
* @param object THREE.Object3D
* @constructor
*/
class AddObjectCommand extends Command {
public object;
constructor( object ) {
super();
this.type = 'AddObjectCommand';
this.object = object;
if ( object !== undefined ) {
this.name = `Add object`;
}
}
execute() {
App.addObject(this.object);
App.select(this.object);
}
undo() {
App.removeObject( this.object );
App.deselect();
}
toJSON() {
const output = super.toJSON();
output.object = this.object.toJSON();
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.object.object.uuid );
if ( this.object === undefined ) {
const loader = new ObjectLoader();
this.object = loader.parse( json.object );
}
}
}
export { AddObjectCommand };
@@ -0,0 +1,64 @@
import {Object3D} from "three";
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param script javascript object
* @constructor
*/
class AddScriptCommand extends Command {
private object: Object3D;
private script: any;
constructor(object:Object3D, script) {
super();
this.type = 'AddScriptCommand';
this.name = 'Add script';
this.object = object;
this.script = script;
}
execute() {
if (App.scripts[this.object.uuid] === undefined) {
App.scripts[this.object.uuid] = [];
}
App.scripts[this.object.uuid].push(this.script);
useDispatchSignal("scriptAdded", this.object,this.script);
}
undo() {
if (App.scripts[ this.object.uuid ] === undefined ) return;
const index = App.scripts[ this.object.uuid ].indexOf( this.script );
if (index !== -1) {
App.scripts[ this.object.uuid ].splice( index, 1 );
}
useDispatchSignal("scriptRemoved", this.object,this.script);
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.script = this.script;
return output;
}
fromJSON(json) {
super.fromJSON( json );
this.script = json.script;
this.object = App.getObjectByUuid(json.objectUuid) as Object3D;
}
}
export { AddScriptCommand };
+35
View File
@@ -0,0 +1,35 @@
/**
* @constructor
*/
class Command {
protected id:number;
protected inMemory:boolean;
public updatable:boolean;
protected type:string;
protected name:string;
constructor() {
this.id = - 1;
this.inMemory = false;
this.updatable = false;
this.type = '';
this.name = '';
}
toJSON() {
const output:any = {};
output.type = this.type;
output.id = this.id;
output.name = this.name;
return output;
}
fromJSON( json ) {
this.inMemory = true;
this.type = json.type;
this.id = json.id;
this.name = json.name;
}
}
export { Command };
@@ -0,0 +1,21 @@
export { AddObjectCommand } from './AddObjectCommand';
export { AddScriptCommand } from './AddScriptCommand';
export { MoveObjectCommand } from './MoveObjectCommand';
export { RemoveObjectCommand } from './RemoveObjectCommand';
export { RemoveScriptCommand } from './RemoveScriptCommand';
export { SetColorCommand } from './SetColorCommand';
export { SetGeometryCommand } from './SetGeometryCommand';
export { SetGeometryValueCommand } from './SetGeometryValueCommand';
export { SetMaterialColorCommand } from './SetMaterialColorCommand';
export { SetMaterialCommand } from './SetMaterialCommand';
export { SetMaterialMapCommand } from './SetMaterialMapCommand';
export { SetMaterialRangeCommand } from './SetMaterialRangeCommand';
export { SetMaterialValueCommand } from './SetMaterialValueCommand';
export { SetMaterialVectorCommand } from './SetMaterialVectorCommand';
export { SetPositionCommand } from './SetPositionCommand';
export { SetRotationCommand } from './SetRotationCommand';
export { SetScaleCommand } from './SetScaleCommand';
export { SetSceneCommand } from './SetSceneCommand';
export { SetScriptValueCommand } from './SetScriptValueCommand';
export { SetUuidCommand } from './SetUuidCommand';
export { SetValueCommand } from './SetValueCommand';
@@ -0,0 +1,127 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param newParent THREE.Object3D
* @param newBefore THREE.Object3D
* @constructor
*/
class MoveObjectCommand extends Command {
public object;
public oldParent;
public oldIndex;
public newParent;
public newIndex;
public newBefore;
constructor(object, newParent, newBefore ) {
super();
this.type = 'MoveObjectCommand';
this.name = 'Move object';
this.object = object;
this.oldParent = ( object !== undefined ) ? object.parent : undefined;
this.oldIndex = ( this.oldParent !== undefined ) ? this.oldParent.children.indexOf( this.object ) : undefined;
this.newParent = newParent;
if ( newBefore !== undefined ) {
this.newIndex = ( newParent !== undefined ) ? newParent.children.indexOf( newBefore ) : undefined;
} else {
this.newIndex = ( newParent !== undefined ) ? newParent.children.length : undefined;
}
if ( this.oldParent === this.newParent && this.newIndex > this.oldIndex ) {
this.newIndex--;
}
this.newBefore = newBefore;
}
execute() {
this.oldParent.remove(this.object);
/** 放置到新组下时不改变世界坐标 **/
// this.newParent.updateWorldMatrix(true, false);
// const _m1 = new Matrix4();
// _m1.copy(this.newParent.matrixWorld).invert();
// if (this.object.parent !== null) {
// this.object.parent.updateWorldMatrix( true, false );
// _m1.multiply( this.object.parent.matrixWorld );
// }
// this.object.applyMatrix4( _m1 );
/** 放置到新组下时不改变世界坐标 End **/
const children = this.newParent.children;
children.splice( this.newIndex, 0, this.object );
this.object.parent = this.newParent;
/** 放置到新组下时不改变世界坐标 **/
// this.object.updateWorldMatrix( false, true );
/** 放置到新组下时不改变世界坐标 End **/
this.object.dispatchEvent({ type: 'added' });
useDispatchSignal("sceneGraphChanged");
}
undo() {
this.newParent.remove(this.object);
/** 撤销时不改变世界坐标 **/
// this.oldParent.updateWorldMatrix(true, false);
// const _m1 = new Matrix4();
// _m1.copy(this.oldParent.matrixWorld).invert();
// if (this.object.parent !== null) {
// this.object.parent.updateWorldMatrix(true, false);
// _m1.multiply( this.object.parent.matrixWorld );
// }
// this.object.applyMatrix4(_m1);
/** 撤销时不改变世界坐标 End **/
const children = this.oldParent.children;
children.splice( this.oldIndex, 0, this.object );
this.object.parent = this.oldParent;
/** 撤销时不改变世界坐标 **/
// this.object.updateWorldMatrix( false, true );
/** 撤销时不改变世界坐标 End **/
this.object.dispatchEvent( { type: 'added' } );
useDispatchSignal("sceneGraphChanged");
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.newParentUuid = this.newParent.uuid;
output.oldParentUuid = this.oldParent.uuid;
output.newIndex = this.newIndex;
output.oldIndex = this.oldIndex;
return output;
}
fromJSON(json) {
super.fromJSON(json);
this.object = App.getObjectByUuid(json.objectUuid);
this.oldParent = App.getObjectByUuid(json.oldParentUuid);
if (this.oldParent === undefined) {
this.oldParent = App.scene;
}
this.newParent = App.getObjectByUuid(json.newParentUuid);
if (this.newParent === undefined) {
this.newParent = App.scene;
}
this.newIndex = json.newIndex;
this.oldIndex = json.oldIndex;
}
}
export { MoveObjectCommand };
@@ -0,0 +1,64 @@
import { Command } from './Command';
import { ObjectLoader } from '../loader/ObjectLoader';
import App from "../app/App";
/**
* @param object THREE.Object3D
* @constructor
*/
class RemoveObjectCommand extends Command {
public object;
public parent;
public index;
constructor( object ) {
super();
this.type = 'RemoveObjectCommand';
this.name = 'Remove object';
this.object = object;
this.parent = ( object !== undefined ) ? object.parent : undefined;
if ( this.parent !== undefined ) {
this.index = this.parent.children.indexOf( this.object );
}
}
execute() {
App.removeObject( this.object );
App.deselect();
}
undo() {
App.addObject( this.object, this.parent, this.index );
App.select( this.object );
}
toJSON() {
const output = super.toJSON();
output.object = this.object.toJSON();
output.index = this.index;
output.parentUuid = this.parent.uuid;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.parent = App.getObjectByUuid( json.parentUuid );
if ( this.parent === undefined ) {
this.parent = App.scene;
}
this.index = json.index;
this.object = App.getObjectByUuid( json.object.object.uuid );
if ( this.object === undefined ) {
const loader = new ObjectLoader();
this.object = loader.parse( json.object );
}
}
}
export { RemoveObjectCommand };
@@ -0,0 +1,68 @@
import {Object3D} from "three";
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param script javascript object
* @constructor
*/
class RemoveScriptCommand extends Command {
private object: Object3D;
private script: any;
private index: number = -1;
constructor(object:Object3D, script) {
super();
this.type = 'RemoveScriptCommand';
this.name = 'Remove script';
this.object = object;
this.script = script;
if (this.object && this.script) {
this.index = App.scripts[this.object.uuid].findIndex((i) => i.name === this.script.name);
}
}
execute() {
if (App.scripts[ this.object.uuid ] === undefined) return;
if (this.index !== -1) {
App.scripts[this.object.uuid].splice( this.index, 1 );
}
useDispatchSignal("scriptRemoved",this.object,this.script);
}
undo() {
if (App.scripts[ this.object.uuid ] === undefined) {
App.scripts[ this.object.uuid ] = [];
}
App.scripts[this.object.uuid].splice(this.index, 0, this.script);
useDispatchSignal("scriptAdded",this.object,this.script);
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.script = this.script;
output.index = this.index;
return output;
}
fromJSON(json) {
super.fromJSON( json );
this.script = json.script;
this.index = json.index;
this.object = App.getObjectByUuid(json.objectUuid) as Object3D;
}
}
export { RemoveScriptCommand };
@@ -0,0 +1,65 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks/useSignal";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param attributeName string
* @param newValue integer representing a hex color value
* @constructor
*/
class SetColorCommand extends Command {
public object;
public attributeName;
public oldValue;
public newValue;
constructor(object, attributeName, newValue ) {
super();
this.type = 'SetColorCommand';
this.name = `Set ${attributeName}`;
this.updatable = true;
this.object = object;
this.attributeName = attributeName;
this.oldValue = (object !== undefined) ? this.object[this.attributeName].getStyle() : undefined;
this.newValue = newValue;
}
execute() {
this.object[ this.attributeName ].setStyle(this.newValue);
useDispatchSignal("objectChanged",this.object);
}
undo() {
this.object[ this.attributeName ].setStyle(this.oldValue);
useDispatchSignal("objectChanged",this.object);
}
update( cmd ) {
this.newValue = cmd.newValue;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.attributeName = json.attributeName;
this.oldValue = json.oldValue;
this.newValue = json.newValue;
}
}
export { SetColorCommand };
@@ -0,0 +1,77 @@
import { Command } from './Command';
import { BufferGeometry,Mesh, InstancedBufferGeometry} from 'three';
import { ObjectLoader } from '../loader/ObjectLoader';
import {useDispatchSignal} from "@/hooks";
import App from "../app/App";
/**
* @param editor Editor
* @param object THREE.Object3D
* @param newGeometry THREE.Geometry
* @constructor
*/
class SetGeometryCommand extends Command {
object:Mesh;
private oldGeometry: BufferGeometry | InstancedBufferGeometry | undefined;
private newGeometry: BufferGeometry | InstancedBufferGeometry
constructor(object:Mesh, newGeometry:BufferGeometry) {
super();
this.type = 'SetGeometryCommand';
this.name = 'Set geometry';
this.updatable = true;
this.object = object;
this.oldGeometry = ( object !== undefined ) ? object.geometry : undefined;
this.newGeometry = newGeometry;
}
execute() {
this.object.geometry.dispose();
this.object.geometry = this.newGeometry;
this.object.geometry.computeBoundingSphere();
useDispatchSignal("geometryChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
undo() {
this.object.geometry.dispose();
this.oldGeometry && (this.object.geometry = this.oldGeometry);
this.object.geometry.computeBoundingSphere();
useDispatchSignal("geometryChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
update(cmd: { newGeometry: BufferGeometry | InstancedBufferGeometry; }) {
this.newGeometry = cmd.newGeometry;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.oldGeometry = this.object.geometry.toJSON();
output.newGeometry = this.newGeometry.toJSON();
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid ) as Mesh;
this.oldGeometry = parseGeometry( json.oldGeometry );
this.newGeometry = parseGeometry( json.newGeometry );
function parseGeometry(data) {
const loader = new ObjectLoader();
return loader.parseGeometries( [ data ] )[ data.uuid ];
}
}
}
export { SetGeometryCommand };
@@ -0,0 +1,64 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks/useSignal";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param attributeName string
* @param newValue number, string, boolean or object
* @constructor
*/
class SetGeometryValueCommand extends Command {
public object;
public attributeName;
public oldValue;
public newValue;
constructor(object, attributeName, newValue ) {
super();
this.type = 'SetGeometryValueCommand';
this.name = `Set geometry.${attributeName}`;
this.object = object;
this.attributeName = attributeName;
this.oldValue = ( object !== undefined ) ? object.geometry[ attributeName ] : undefined;
this.newValue = newValue;
}
execute() {
this.object.geometry[ this.attributeName ] = this.newValue;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("geometryChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
undo() {
this.object.geometry[ this.attributeName ] = this.oldValue;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("geometryChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.attributeName = json.attributeName;
this.oldValue = json.oldValue;
this.newValue = json.newValue;
}
}
export { SetGeometryValueCommand };
@@ -0,0 +1,69 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param attributeName string
* @param newValue integer representing a hex color value
* @constructor
*/
class SetMaterialColorCommand extends Command {
public object;
public material;
public oldValue;
public newValue;
public attributeName;
constructor(object, attributeName, newValue, materialSlot ) {
super();
this.type = 'SetMaterialColorCommand';
this.name = `Set material.${attributeName}`;
this.updatable = true;
this.object = object;
this.material = (this.object !== undefined) ? App.getObjectMaterial(object, materialSlot) : undefined;
this.oldValue = (this.material !== undefined) ? this.material[attributeName].getHex() : undefined;
this.newValue = newValue;
this.attributeName = attributeName;
}
execute() {
this.material[ this.attributeName ].setHex( this.newValue );
useDispatchSignal("materialChanged",this.material);
}
undo() {
this.material[ this.attributeName ].setHex( this.oldValue );
useDispatchSignal("materialChanged",this.material);
}
update( cmd ) {
this.newValue = cmd.newValue;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.attributeName = json.attributeName;
this.oldValue = json.oldValue;
this.newValue = json.newValue;
}
}
export { SetMaterialColorCommand };
@@ -0,0 +1,66 @@
import { Command } from './Command';
import { ObjectLoader } from '../loader/ObjectLoader';
import {useDispatchSignal} from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param newMaterial THREE.Material
* @constructor
*/
class SetMaterialCommand extends Command {
private object;
private materialSlot;
private oldMaterial;
private newMaterial;
constructor(object, newMaterial, materialSlot? ) {
super();
this.type = 'SetMaterialCommand';
this.name = 'Set new material';
this.object = object;
this.materialSlot = materialSlot;
this.oldMaterial = App.getObjectMaterial( object, materialSlot );
this.newMaterial = newMaterial;
}
execute() {
App.setObjectMaterial( this.object, this.materialSlot, this.newMaterial );
useDispatchSignal("materialChanged",this.newMaterial);
}
undo() {
App.setObjectMaterial( this.object, this.materialSlot, this.oldMaterial );
useDispatchSignal("materialChanged",this.oldMaterial);
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.oldMaterial = this.oldMaterial.toJSON();
output.newMaterial = this.newMaterial.toJSON();
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.oldMaterial = parseMaterial( json.oldMaterial );
this.newMaterial = parseMaterial( json.newMaterial );
function parseMaterial( json ) {
const loader = new ObjectLoader();
//@ts-ignore
const images = loader.parseImages( json.images );
const textures = loader.parseTextures( json.textures, images );
const materials = loader.parseMaterials( [ json ], textures );
return materials[ json.uuid ];
}
}
}
export { SetMaterialCommand };
@@ -0,0 +1,125 @@
import { Command } from './Command';
import { ObjectLoader } from '../loader/ObjectLoader';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param mapName string
* @param newMap THREE.Texture
* @constructor
*/
class SetMaterialMapCommand extends Command {
public object;
private material;
private oldMap;
private newMap;
private mapName;
constructor( object, mapName, newMap, materialSlot ) {
super();
this.type = 'SetMaterialMapCommand';
this.name = `Set material.${mapName}`;
this.object = object;
this.material = App.getObjectMaterial( object, materialSlot );
this.oldMap = ( object !== undefined ) ? this.material[ mapName ] : undefined;
this.newMap = newMap;
this.mapName = mapName;
}
execute() {
if ( this.oldMap !== null && this.oldMap !== undefined ) this.oldMap.dispose();
this.material[ this.mapName ] = this.newMap;
this.material.needsUpdate = true;
useDispatchSignal("materialChanged",this.material)
}
undo() {
this.material[ this.mapName ] = this.oldMap;
this.material.needsUpdate = true;
useDispatchSignal("materialChanged",this.material)
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.mapName = this.mapName;
output.newMap = serializeMap( this.newMap );
output.oldMap = serializeMap( this.oldMap );
return output;
// serializes a map (THREE.Texture)
function serializeMap( map ) {
if ( map === null || map === undefined ) return null;
const meta = {
geometries: {},
materials: {},
textures: {},
images: {}
};
const json = map.toJSON( meta );
const images = extractFromCache( meta.images );
if ( images.length > 0 ) json.images = images;
json.sourceFile = map.sourceFile;
return json;
}
// Note: The function 'extractFromCache' is copied from Object3D.toJSON()
// extract data from the cache hash
// remove metadata on each item
// and return as array
function extractFromCache( cache ) {
const values:any = [];
for ( const key in cache ) {
const data = cache[ key ];
delete data.metadata;
values.push( data );
}
return values;
}
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.mapName = json.mapName;
this.oldMap = parseTexture( json.oldMap );
this.newMap = parseTexture( json.newMap );
function parseTexture( json ) {
let map;
if ( json !== null ) {
const loader = new ObjectLoader();
const images = loader.parseImages( json.images,()=>{} );
const textures = loader.parseTextures( [ json ], images );
map = textures[ json.uuid ];
map.sourceFile = json.sourceFile;
}
return map;
}
}
}
export { SetMaterialMapCommand };
@@ -0,0 +1,76 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param attributeName string
* @param newMinValue number
* @param newMaxValue number
* @constructor
*/
class SetMaterialRangeCommand extends Command {
public object;
public material;
public oldValue;
public newValue;
public attributeName;
constructor(object, attributeName, newMinValue, newMaxValue, materialSlot ) {
super();
this.type = 'SetMaterialRangeCommand';
this.name = `Set material.${attributeName}`;
this.updatable = true;
this.object = object;
this.material = App.getObjectMaterial( object, materialSlot );
this.oldValue = ( this.material !== undefined && this.material[ attributeName ] !== undefined ) ? [ ...this.material[ attributeName ] ] : undefined;
this.newValue = [ newMinValue, newMaxValue ];
this.attributeName = attributeName;
}
execute() {
this.material[ this.attributeName ] = [ ...this.newValue ];
this.material.needsUpdate = true;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("materialChanged",this.material);
}
undo() {
this.material[ this.attributeName ] = [ ...this.oldValue ];
this.material.needsUpdate = true;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("materialChanged",this.material);
}
update( cmd ) {
this.newValue = [ ...cmd.newValue ];
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = [ ...this.oldValue ];
output.newValue = [ ...this.newValue ];
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.attributeName = json.attributeName;
this.oldValue = [ ...json.oldValue ];
this.newValue = [ ...json.newValue ];
this.object = App.getObjectByUuid( json.objectUuid );
}
}
export { SetMaterialRangeCommand };
@@ -0,0 +1,75 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param attributeName string
* @param newValue number, string, boolean or object
* @constructor
*/
class SetMaterialValueCommand extends Command {
public object;
public material;
public oldValue;
public newValue;
public attributeName;
constructor(object, attributeName, newValue, materialSlot = 0 ) {
super();
this.type = 'SetMaterialValueCommand';
this.name = `Set material.${attributeName}`;
this.updatable = true;
this.object = object;
this.material = App.getObjectMaterial( object, materialSlot );
this.oldValue = ( this.material !== undefined ) ? this.material[ attributeName ] : undefined;
this.newValue = newValue;
this.attributeName = attributeName;
}
execute() {
this.material[ this.attributeName ] = this.newValue;
this.material.needsUpdate = true;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("materialChanged",this.material);
}
undo() {
this.material[ this.attributeName ] = this.oldValue;
this.material.needsUpdate = true;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("materialChanged",this.material);
}
update( cmd ) {
this.newValue = cmd.newValue;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.attributeName = json.attributeName;
this.oldValue = json.oldValue;
this.newValue = json.newValue;
this.object = App.getObjectByUuid( json.objectUuid );
}
}
export { SetMaterialValueCommand };
@@ -0,0 +1,67 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
class SetMaterialVectorCommand extends Command {
public object;
private material;
private oldValue;
private newValue;
private attributeName;
constructor(object, attributeName, newValue, materialSlot) {
super();
this.type = 'SetMaterialColorCommand';
this.name = `Set material.${attributeName}`;
this.updatable = true;
this.object = object;
this.material = App.getObjectMaterial( object, materialSlot );
this.attributeName = attributeName;
this.oldValue = (this.material !== undefined) ? this.attribute.toArray() : undefined;
this.newValue = newValue;
}
get attribute() {
return this.attributeName.split('.').reduce((obj, key) => obj[key], this.material);
}
execute() {
this.attribute.fromArray(this.newValue);
useDispatchSignal("materialChanged",this.material)
}
undo() {
this.attribute.fromArray(this.oldValue);
useDispatchSignal("materialChanged",this.material)
}
update( cmd ) {
this.newValue = cmd.newValue;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.attributeName = json.attributeName;
this.oldValue = json.oldValue;
this.newValue = json.newValue;
}
}
export { SetMaterialVectorCommand };
@@ -0,0 +1,68 @@
import { Vector3 } from 'three';
import { Command } from './Command';
import { useDispatchSignal } from '@/hooks';
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param newValue THREE.Vector3
* @param optionaloldValue THREE.Vector3
* @constructor
*/
class SetPositionCommand extends Command {
public object;
public oldValue;
public newValue;
constructor(object, newValue, optionaloldValue? ) {
super();
this.type = 'SetPositionCommand';
this.name = `Set position`;
this.updatable = true;
this.object = object;
if ( object !== undefined && newValue !== undefined ) {
this.oldValue = object.position.clone();
this.newValue = newValue.clone();
}
if ( optionaloldValue !== undefined ) {
this.oldValue = optionaloldValue.clone();
}
}
execute() {
this.object.position.copy( this.newValue );
this.object.updateMatrixWorld( true );
useDispatchSignal("objectChanged",this.object)
}
undo() {
this.object.position.copy( this.oldValue );
this.object.updateMatrixWorld( true );
useDispatchSignal("objectChanged",this.object);
}
update( command ) {
this.newValue.copy( command.newValue );
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.oldValue = this.oldValue.toArray();
output.newValue = this.newValue.toArray();
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.oldValue = new Vector3().fromArray( json.oldValue );
this.newValue = new Vector3().fromArray( json.newValue );
}
}
export { SetPositionCommand };
@@ -0,0 +1,71 @@
import { Euler } from 'three';
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param newValue THREE.Euler
* @param optionaloldValue THREE.Euler
* @constructor
*/
class SetRotationCommand extends Command {
public object;
public oldValue;
public newValue;
constructor(object, newValue, optionaloldValue ) {
super();
this.type = 'SetRotationCommand';
this.name = `Set rotation`;
this.updatable = true;
this.object = object;
if ( object !== undefined && newValue !== undefined ) {
this.oldValue = object.rotation.clone();
this.newValue = newValue.clone();
}
if ( optionaloldValue !== undefined ) {
this.oldValue = optionaloldValue.clone();
}
}
execute() {
this.object.rotation.copy( this.newValue );
this.object.updateMatrixWorld( true );
useDispatchSignal("objectChanged",this.object);
}
undo() {
this.object.rotation.copy( this.oldValue );
this.object.updateMatrixWorld( true );
useDispatchSignal("objectChanged",this.object);
}
update( command ) {
this.newValue.copy( command.newValue );
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.oldValue = this.oldValue.toArray();
output.newValue = this.newValue.toArray();
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.oldValue = new Euler().fromArray( json.oldValue );
this.newValue = new Euler().fromArray( json.newValue );
}
}
export { SetRotationCommand };
@@ -0,0 +1,71 @@
import { Vector3 } from 'three';
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks/useSignal";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param newValue THREE.Vector3
* @param optionaloldValue THREE.Vector3
* @constructor
*/
class SetScaleCommand extends Command {
public object;
public oldValue;
public newValue;
constructor(object, newValue, optionaloldValue ) {
super();
this.type = 'SetScaleCommand';
this.name = `Set scale`;
this.updatable = true;
this.object = object;
if ( object !== undefined && newValue !== undefined ) {
this.oldValue = object.scale.clone();
this.newValue = newValue.clone();
}
if ( optionaloldValue !== undefined ) {
this.oldValue = optionaloldValue.clone();
}
}
execute() {
this.object.scale.copy( this.newValue );
this.object.updateMatrixWorld( true );
useDispatchSignal("objectChanged",this.object);
}
undo() {
this.object.scale.copy( this.oldValue );
this.object.updateMatrixWorld( true );
useDispatchSignal("objectChanged",this.object);
}
update( command ) {
this.newValue.copy( command.newValue );
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.oldValue = this.oldValue.toArray();
output.newValue = this.newValue.toArray();
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.object = App.getObjectByUuid( json.objectUuid );
this.oldValue = new Vector3().fromArray( json.oldValue );
this.newValue = new Vector3().fromArray( json.newValue );
}
}
export { SetScaleCommand };
@@ -0,0 +1,85 @@
import {Scene} from "three";
import { Command } from './Command';
import { SetUuidCommand } from './SetUuidCommand';
import { SetValueCommand } from './SetValueCommand';
import { AddObjectCommand } from './AddObjectCommand';
import {useSignal} from "@/hooks";
import App from "../app/App";
const {setActive,dispatch} = useSignal();
/**
* @param scene containing children to import
* @constructor
*/
class SetSceneCommand extends Command {
private cmdArray: any[];
constructor(scene:Scene) {
super();
this.type = 'SetSceneCommand';
this.name = 'Set scene';
this.cmdArray = [];
if (scene !== undefined) {
this.cmdArray.push( new SetUuidCommand(App.scene, scene.uuid));
this.cmdArray.push( new SetValueCommand(App.scene, 'name', scene.name));
this.cmdArray.push( new SetValueCommand(App.scene, 'userData', JSON.parse(JSON.stringify(scene.userData))));
while ( scene.children.length > 0 ) {
const child = scene.children.pop();
this.cmdArray.push(new AddObjectCommand(child));
}
}
}
execute() {
setActive("sceneGraphChanged",false);
for (let i = 0; i < this.cmdArray.length; i++) {
this.cmdArray[i].execute();
}
setActive("sceneGraphChanged",true);
dispatch("sceneGraphChanged");
}
undo() {
setActive("sceneGraphChanged",false);
for (let i = this.cmdArray.length - 1; i >= 0; i--) {
this.cmdArray[i].undo();
}
setActive("sceneGraphChanged",true);
dispatch("sceneGraphChanged");
}
toJSON() {
const output = super.toJSON();
const cmds:string[] = [];
for ( let i = 0; i < this.cmdArray.length; i ++ ) {
cmds.push(this.cmdArray[ i ].toJSON());
}
output.cmds = cmds;
return output;
}
fromJSON(json) {
super.fromJSON( json );
const cmds = json.cmds;
for ( let i = 0; i < cmds.length; i ++ ) {
// @ts-ignore
const cmd = new window[cmds[i].type](); // 创建类型为“json.type”的新对象
cmd.fromJSON(cmds[i]);
this.cmdArray.push(cmd);
}
}
}
export { SetSceneCommand };
@@ -0,0 +1,74 @@
import { Object3D } from 'three';
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param script javascript object
* @param attributeName string
* @param newValue string, object
* @constructor
*/
class SetScriptValueCommand extends Command {
private object: Object3D;
private script: IScript.IStruct;
private attributeName: string;
private oldValue: any;
private newValue: string;
constructor(object:Object3D, script:IScript.IStruct, attributeName:string, newValue:string) {
super();
this.type = 'SetScriptValueCommand';
this.name = `Set script.${attributeName}`;
this.updatable = true;
this.object = object;
this.script = script;
this.attributeName = attributeName;
this.oldValue = ( script !== undefined ) ? script[ this.attributeName ] : undefined;
this.newValue = newValue;
}
execute() {
this.script[this.attributeName] = this.newValue;
useDispatchSignal("scriptChanged",this.attributeName,this.object,this.script);
}
undo() {
this.script[this.attributeName] = this.oldValue;
useDispatchSignal("scriptChanged",this.attributeName,this.object,this.script);
}
update(cmd) {
this.newValue = cmd.newValue;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.index = App.scripts[this.object.uuid].indexOf(this.script);
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON(json) {
super.fromJSON(json);
this.oldValue = json.oldValue;
this.newValue = json.newValue;
this.attributeName = json.attributeName;
this.object = App.getObjectByUuid(json.objectUuid) as Object3D;
this.script = App.scripts[json.objectUuid][json.index];
}
}
export { SetScriptValueCommand };
@@ -0,0 +1,61 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param newValue string
* @constructor
*/
class SetUuidCommand extends Command {
public object;
public oldValue;
public newValue;
constructor(object, newValue ) {
super();
this.type = 'SetUuidCommand';
this.name = `Update uuid`;
this.object = object;
this.oldValue = ( object !== undefined ) ? object.uuid : undefined;
this.newValue = newValue;
}
execute() {
this.object.uuid = this.newValue;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
undo() {
this.object.uuid = this.oldValue;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
toJSON() {
const output = super.toJSON();
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.oldValue = json.oldValue;
this.newValue = json.newValue;
this.object = App.getObjectByUuid( json.oldValue );
if ( this.object === undefined ) {
this.object = App.getObjectByUuid( json.newValue );
}
}
}
export { SetUuidCommand };
@@ -0,0 +1,68 @@
import { Command } from './Command';
import { useDispatchSignal } from "@/hooks";
import App from "../app/App";
/**
* @param object THREE.Object3D
* @param attributeName string
* @param newValue number, string, boolean or object
* @constructor
*/
class SetValueCommand extends Command {
public object;
public attributeName;
public oldValue;
public newValue;
constructor(object, attributeName, newValue) {
super();
this.type = 'SetValueCommand';
this.name = `Set ${attributeName}`;
this.updatable = true;
this.object = object;
this.attributeName = attributeName;
this.oldValue = ( object !== undefined ) ? object[ attributeName ] : undefined;
this.newValue = newValue;
}
execute() {
this.object[ this.attributeName ] = this.newValue;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
undo() {
this.object[ this.attributeName ] = this.oldValue;
useDispatchSignal("objectChanged",this.object);
useDispatchSignal("sceneGraphChanged");
}
update( cmd ) {
this.newValue = cmd.newValue;
}
toJSON() {
const output = super.toJSON();
output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldValue = this.oldValue;
output.newValue = this.newValue;
return output;
}
fromJSON( json ) {
super.fromJSON( json );
this.attributeName = json.attributeName;
this.oldValue = json.oldValue;
this.newValue = json.newValue;
this.object = App.getObjectByUuid( json.objectUuid );
}
}
export { SetValueCommand };