diff --git a/packages/editor/src/components/EditorSidebar.vue b/packages/editor/src/components/EditorSidebar.vue index 6383d7f..a725f79 100644 --- a/packages/editor/src/components/EditorSidebar.vue +++ b/packages/editor/src/components/EditorSidebar.vue @@ -79,12 +79,18 @@ const rerenderSelection = () => { }; register('initialized', () => createSceneMap()); +register('sceneJoin', () => createSceneMap()); +register('sceneLeave', () => createSceneMap()); register('selected', (event) => updateSelectionMap(event)); register('deselected', (event) => updateSelectionMap(event)); register('change', (event) => { if (['name', 'visible', 'parent'].includes(event.property)) createSceneMap(); rerenderSelection(); }); +register('reset', () => { + createSceneMap(); + rerenderSelection(); +}); onMounted(() => createSceneMap()); diff --git a/packages/editor/src/components/Toolbar.vue b/packages/editor/src/components/Toolbar.vue index b3cbe37..cea74ca 100644 --- a/packages/editor/src/components/Toolbar.vue +++ b/packages/editor/src/components/Toolbar.vue @@ -1,9 +1,36 @@ diff --git a/packages/editor/src/components/menu/Menu.vue b/packages/editor/src/components/menu/Menu.vue new file mode 100644 index 0000000..ee211d2 --- /dev/null +++ b/packages/editor/src/components/menu/Menu.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/packages/editor/src/components/sidebar/SidebarForm.vue b/packages/editor/src/components/sidebar/SidebarForm.vue index 688499a..b227ff1 100644 --- a/packages/editor/src/components/sidebar/SidebarForm.vue +++ b/packages/editor/src/components/sidebar/SidebarForm.vue @@ -4,6 +4,7 @@ { emit('update', object, property, value); }; +function toCapitalizedWords(name: string) { + const words = name.match(/[A-Za-z][a-z]*/g) || []; + + return words.map(capitalize).join(' '); +} + +function capitalize(word: string) { + return word.charAt(0).toUpperCase() + word.substring(1); +} + const formFields = computed(() => { // TODO: multi-edit const object = props.selection[0]; @@ -54,6 +66,7 @@ const formFields = computed(() => { if (property.type === String || property.type === Number) { fields.push({ name: property.name, + label: toCapitalizedWords(property.name), value: (object as unknown as Record)[property.name], type: property.type === String ? 'string' : 'number', component: Field, @@ -63,6 +76,7 @@ const formFields = computed(() => { if (property.type === Vector3 || property.type === Euler) { fields.push({ name: property.name, + label: toCapitalizedWords(property.name), value: (object as unknown as Record)[property.name], type: property.type === Vector3 ? 'vector' : 'euler', component: Vector3Field, @@ -72,6 +86,7 @@ const formFields = computed(() => { if (property.type === Color) { fields.push({ name: property.name, + label: toCapitalizedWords(property.name), value: (object as unknown as Record)[property.name], component: ColorPicker, }); @@ -80,6 +95,7 @@ const formFields = computed(() => { if (property.type === Boolean) { fields.push({ name: property.name, + label: toCapitalizedWords(property.name), value: (object as unknown as Record)[property.name], component: Checkbox, }); diff --git a/packages/editor/src/components/sidebar/SidebarPanel.vue b/packages/editor/src/components/sidebar/SidebarPanel.vue index 48131db..74761fa 100644 --- a/packages/editor/src/components/sidebar/SidebarPanel.vue +++ b/packages/editor/src/components/sidebar/SidebarPanel.vue @@ -10,6 +10,7 @@ display: flex; flex-direction: column; overflow: hidden; + background-color: #f7f7f7; &-title { background-color: #e5e5e5; diff --git a/packages/editor/src/components/sidebar/SidebarRow.vue b/packages/editor/src/components/sidebar/SidebarRow.vue index 06b1f1f..c274a9a 100644 --- a/packages/editor/src/components/sidebar/SidebarRow.vue +++ b/packages/editor/src/components/sidebar/SidebarRow.vue @@ -53,7 +53,7 @@ const filtered = (items: Object3D[]) => flex-direction: column; &-button { - background-color: #efefef; + background-color: transparent; user-select: none; appearance: none; padding: 8px; @@ -62,7 +62,7 @@ const filtered = (items: Object3D[]) => cursor: pointer; &.selected { - background-color: #ffffff; + background-color: #bcefff; } } } diff --git a/packages/editor/src/editor/core/history.ts b/packages/editor/src/editor/core/history.ts index 8a66db0..d74a749 100644 --- a/packages/editor/src/editor/core/history.ts +++ b/packages/editor/src/editor/core/history.ts @@ -179,6 +179,11 @@ export class HistoryComponent extends EngineComponent { const undo = this.undo.bind(this); const redo = this.redo.bind(this); + const resetEvent = () => { + this.history.length = 0; + this.restory.length = 0; + }; + this.events.addListener('change', changeEvent); this.events.addListener('transformStart', transformStart); this.events.addListener('transformEnd', transformEnd); @@ -186,6 +191,7 @@ export class HistoryComponent extends EngineComponent { this.events.addListener('remove', removeEvent); this.events.addListener('undo', undo); this.events.addListener('redo', redo); + this.events.addListener('resetHistory', resetEvent); return () => { this.events.removeEventListener('change', changeEvent); @@ -195,6 +201,7 @@ export class HistoryComponent extends EngineComponent { this.events.removeEventListener('remove', removeEvent); this.events.removeEventListener('undo', undo); this.events.removeEventListener('redo', redo); + this.events.removeEventListener('resetHistory', resetEvent); }; } } diff --git a/packages/editor/src/editor/core/workspace.ts b/packages/editor/src/editor/core/workspace.ts index ebdf6c9..3157bf2 100644 --- a/packages/editor/src/editor/core/workspace.ts +++ b/packages/editor/src/editor/core/workspace.ts @@ -12,6 +12,7 @@ import { Wedge, WedgeCorner, WedgeInnerCorner, + World, } from '@freeblox/engine'; import { AxesHelper, @@ -31,7 +32,6 @@ import { } from '../types/events'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js'; -import { World } from '@freeblox/engine/dist/gameobjects/world.object'; /** * This component does most of the work related to editing the level. @@ -349,6 +349,25 @@ export class WorkspaceComponent extends EngineComponent { if (this.cutOperation) this.cutOperation = false; }; + const resetEvent = () => { + const oldSelection = [...this.selection]; + this.cutOperation = false; + this.transforming = false; + this.selection.length = 0; + this.clipboard.length = 0; + this.transformPosition = undefined; + this.transformRotation = undefined; + this.transformScale = undefined; + this.transforming = false; + oldSelection.forEach((selection) => + this.events.emit('deselected', { + object: selection, + selection: [], + }) + ); + this.events.emit('resetHistory'); + }; + this.events.addListener('mouseDown', mouseDownEventHandler); this.events.addListener('mouseMove', mouseMoveEventHandler); this.events.addListener('mouseUp', mouseUpEventHandler); @@ -364,6 +383,7 @@ export class WorkspaceComponent extends EngineComponent { this.events.addListener('paste', pasteEvent); this.events.addListener('delete', deleteEvent); this.events.addListener('undo', undoEvent); + this.events.addListener('reset', resetEvent); return () => { this.events.removeEventListener('mouseDown', mouseDownEventHandler); @@ -384,6 +404,7 @@ export class WorkspaceComponent extends EngineComponent { this.events.removeEventListener('paste', pasteEvent); this.events.removeEventListener('delete', deleteEvent); this.events.removeEventListener('undo', undoEvent); + this.events.removeEventListener('reset', resetEvent); }; } diff --git a/packages/editor/src/editor/types/events.ts b/packages/editor/src/editor/types/events.ts index 0dde2bd..a1039ec 100644 --- a/packages/editor/src/editor/types/events.ts +++ b/packages/editor/src/editor/types/events.ts @@ -44,6 +44,7 @@ export type Events = { copy: () => void; delete: () => void; paste: (event: Object3D | undefined) => void; + resetHistory: () => void; }; export type EditorEvents = Events & EngineEvents; diff --git a/packages/engine/src/assets/manager.ts b/packages/engine/src/assets/manager.ts index 8183dca..db2140a 100644 --- a/packages/engine/src/assets/manager.ts +++ b/packages/engine/src/assets/manager.ts @@ -92,6 +92,13 @@ export class AssetManagerFactory { })); } + /** + * Free all assets from memory + */ + freeAll() { + this.assets.length = 0; + } + /** * Load texture * @param path Path diff --git a/packages/engine/src/components/level.ts b/packages/engine/src/components/level.ts index 3878583..f3b4e7c 100644 --- a/packages/engine/src/components/level.ts +++ b/packages/engine/src/components/level.ts @@ -15,6 +15,7 @@ import { World } from '../gameobjects/world.object'; import { instancableGameObjects } from '../gameobjects'; import { Object3D } from 'three'; import { GameObject } from '../types/game-object'; +import { environmentDefaults } from '../defaults/environment'; /** * Game level management component @@ -113,16 +114,25 @@ export class LevelComponent extends EngineComponent { const instanceEvent = (event: InstanceEvent) => this.createObject(event.type, event.parent); + const resetEvent = () => { + this.world.clear(); + assetManager.freeAll(); + this.events.emit('setEnvironment', environmentDefaults); + Object.assign(this.environment, environmentDefaults); + }; + this.events.addListener('change', changeEvent); this.events.addListener('remove', removeEvent); this.events.addListener('reparent', reparentEvent); this.events.addListener('instance', instanceEvent); + this.events.addListener('reset', resetEvent); return () => { this.events.removeEventListener('change', changeEvent); this.events.removeEventListener('remove', removeEvent); this.events.removeEventListener('reparent', reparentEvent); this.events.removeEventListener('instance', instanceEvent); + this.events.removeEventListener('reset', resetEvent); }; } } diff --git a/packages/engine/src/defaults/environment.ts b/packages/engine/src/defaults/environment.ts new file mode 100644 index 0000000..ec03971 --- /dev/null +++ b/packages/engine/src/defaults/environment.ts @@ -0,0 +1,10 @@ +import { Color, Vector3 } from 'three'; + +export const environmentDefaults = { + sunColor: new Color(0xffffff), + sunPosition: new Vector3(1, 1, 1), + sunStrength: 1, + ambientColor: new Color(0x8a8a8a), + ambientStrength: 1, + clearColor: new Color(0x00aaff), +}; diff --git a/packages/engine/src/gameobjects/environment.object.ts b/packages/engine/src/gameobjects/environment.object.ts index fe7f3c0..9f08f18 100644 --- a/packages/engine/src/gameobjects/environment.object.ts +++ b/packages/engine/src/gameobjects/environment.object.ts @@ -5,6 +5,7 @@ import { SerializedObject, } from '../types/game-object'; import { Property } from '../types/property'; +import { environmentDefaults } from '../defaults/environment'; export const environmentEditorProperties: EditorProperties = { sunColor: new Property('sunColor', Color, true, []), @@ -20,12 +21,12 @@ export class Environment extends GameObject { public name = Environment.name; public virtual = true; - sunColor = new Color(0xffffff); - sunPosition = new Vector3(1, 1, 1); - sunStrength = 1; - ambientColor = new Color(0x8a8a8a); - ambientStrength = 1; - clearColor = new Color(0x00aaff); + sunColor = environmentDefaults.sunColor.clone(); + sunPosition = environmentDefaults.sunPosition.clone(); + sunStrength = environmentDefaults.sunStrength; + ambientColor = environmentDefaults.ambientColor.clone(); + ambientStrength = environmentDefaults.ambientStrength; + clearColor = environmentDefaults.clearColor.clone(); constructor() { super(environmentEditorProperties); diff --git a/packages/engine/src/gameobjects/index.ts b/packages/engine/src/gameobjects/index.ts index 764b224..318d1f5 100644 --- a/packages/engine/src/gameobjects/index.ts +++ b/packages/engine/src/gameobjects/index.ts @@ -17,4 +17,5 @@ export const instancableGameObjects: Record> = { }; export * from './environment.object'; +export * from './world.object'; export { Cylinder, Brick, Sphere, Wedge, WedgeCorner, WedgeInnerCorner }; diff --git a/packages/engine/src/index.ts b/packages/engine/src/index.ts index f548cbd..198d8d4 100644 --- a/packages/engine/src/index.ts +++ b/packages/engine/src/index.ts @@ -4,3 +4,4 @@ export * from './types'; export * from './components'; export * from './gameobjects'; export * from './assets'; +export * from './defaults/environment'; diff --git a/packages/engine/src/types/events.ts b/packages/engine/src/types/events.ts index 60d05f7..f73496e 100644 --- a/packages/engine/src/types/events.ts +++ b/packages/engine/src/types/events.ts @@ -79,4 +79,5 @@ export type EngineEvents = { sceneJoin: (event: Object3D) => void; sceneLeave: (event: Object3D) => void; initialized: () => void; + reset: () => void; };