auto-git:
[change] src/app/editor-store.ts [change] src/viewport-three/viewport-host.ts
This commit is contained in:
@@ -20,6 +20,7 @@ export interface EditorStoreState {
|
|||||||
canUndo: boolean;
|
canUndo: boolean;
|
||||||
canRedo: boolean;
|
canRedo: boolean;
|
||||||
lastCommandLabel: string | null;
|
lastCommandLabel: string | null;
|
||||||
|
storageAvailable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EditorStoreOptions {
|
interface EditorStoreOptions {
|
||||||
@@ -212,7 +213,8 @@ export class EditorStore {
|
|||||||
toolMode: this.toolMode,
|
toolMode: this.toolMode,
|
||||||
canUndo: this.history.canUndo(),
|
canUndo: this.history.canUndo(),
|
||||||
canRedo: this.history.canRedo(),
|
canRedo: this.history.canRedo(),
|
||||||
lastCommandLabel: this.lastCommandLabel
|
lastCommandLabel: this.lastCommandLabel,
|
||||||
|
storageAvailable: this.storage !== null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
LineSegments,
|
LineSegments,
|
||||||
Mesh,
|
Mesh,
|
||||||
MeshStandardMaterial,
|
MeshStandardMaterial,
|
||||||
|
Plane,
|
||||||
PerspectiveCamera,
|
PerspectiveCamera,
|
||||||
Raycaster,
|
Raycaster,
|
||||||
Scene,
|
Scene,
|
||||||
@@ -23,10 +24,13 @@ import {
|
|||||||
} from "three";
|
} from "three";
|
||||||
|
|
||||||
import { isBrushFaceSelected, isBrushSelected, type EditorSelection } from "../core/selection";
|
import { isBrushFaceSelected, isBrushSelected, type EditorSelection } from "../core/selection";
|
||||||
|
import type { ToolMode } from "../core/tool-mode";
|
||||||
|
import type { Vec3 } from "../core/vector";
|
||||||
import type { SceneDocument, WorldSettings } from "../document/scene-document";
|
import type { SceneDocument, WorldSettings } from "../document/scene-document";
|
||||||
import { getPlayerStartEntities } from "../entities/entity-instances";
|
import { getPlayerStartEntities } from "../entities/entity-instances";
|
||||||
import { BOX_FACE_IDS, type BoxBrush, type BoxFaceId } from "../document/brushes";
|
import { BOX_FACE_IDS, DEFAULT_BOX_BRUSH_SIZE, type BoxBrush, type BoxFaceId } from "../document/brushes";
|
||||||
import { applyBoxBrushFaceUvsToGeometry } from "../geometry/box-face-uvs";
|
import { applyBoxBrushFaceUvsToGeometry } from "../geometry/box-face-uvs";
|
||||||
|
import { DEFAULT_GRID_SIZE, snapValueToGrid } from "../geometry/grid-snapping";
|
||||||
import { createStarterMaterialSignature, createStarterMaterialTexture } from "../materials/starter-material-textures";
|
import { createStarterMaterialSignature, createStarterMaterialTexture } from "../materials/starter-material-textures";
|
||||||
import type { MaterialDef } from "../materials/starter-material-library";
|
import type { MaterialDef } from "../materials/starter-material-library";
|
||||||
|
|
||||||
@@ -42,6 +46,8 @@ const SELECTED_FACE_FALLBACK_COLOR = 0xcf7b42;
|
|||||||
const SELECTED_FACE_EMISSIVE = 0x4a2814;
|
const SELECTED_FACE_EMISSIVE = 0x4a2814;
|
||||||
const PLAYER_START_COLOR = 0x7cb7ff;
|
const PLAYER_START_COLOR = 0x7cb7ff;
|
||||||
const PLAYER_START_SELECTED_COLOR = 0xf3be8f;
|
const PLAYER_START_SELECTED_COLOR = 0xf3be8f;
|
||||||
|
const BOX_CREATE_PREVIEW_FILL = 0x89b6ff;
|
||||||
|
const BOX_CREATE_PREVIEW_EDGE = 0xf3be8f;
|
||||||
|
|
||||||
interface CachedMaterialTexture {
|
interface CachedMaterialTexture {
|
||||||
signature: string;
|
signature: string;
|
||||||
@@ -63,13 +69,37 @@ export class ViewportHost {
|
|||||||
private readonly entityGroup = new Group();
|
private readonly entityGroup = new Group();
|
||||||
private readonly raycaster = new Raycaster();
|
private readonly raycaster = new Raycaster();
|
||||||
private readonly pointer = new Vector2();
|
private readonly pointer = new Vector2();
|
||||||
|
private readonly boxCreateIntersection = new Vector3();
|
||||||
|
private readonly boxCreatePlane = new Plane(new Vector3(0, 1, 0), 0);
|
||||||
private readonly brushRenderObjects = new Map<string, BrushRenderObjects>();
|
private readonly brushRenderObjects = new Map<string, BrushRenderObjects>();
|
||||||
private readonly playerStartRenderObjects = new Map<string, PlayerStartRenderObjects>();
|
private readonly playerStartRenderObjects = new Map<string, PlayerStartRenderObjects>();
|
||||||
private readonly materialTextureCache = new Map<string, CachedMaterialTexture>();
|
private readonly materialTextureCache = new Map<string, CachedMaterialTexture>();
|
||||||
|
private readonly boxCreatePreviewMesh = new Mesh(
|
||||||
|
new BoxGeometry(DEFAULT_BOX_BRUSH_SIZE.x, DEFAULT_BOX_BRUSH_SIZE.y, DEFAULT_BOX_BRUSH_SIZE.z),
|
||||||
|
new MeshStandardMaterial({
|
||||||
|
color: BOX_CREATE_PREVIEW_FILL,
|
||||||
|
emissive: BOX_CREATE_PREVIEW_FILL,
|
||||||
|
emissiveIntensity: 0.12,
|
||||||
|
roughness: 0.68,
|
||||||
|
metalness: 0.02,
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.22
|
||||||
|
})
|
||||||
|
);
|
||||||
|
private readonly boxCreatePreviewEdges = new LineSegments(
|
||||||
|
new EdgesGeometry(this.boxCreatePreviewMesh.geometry),
|
||||||
|
new LineBasicMaterial({
|
||||||
|
color: BOX_CREATE_PREVIEW_EDGE
|
||||||
|
})
|
||||||
|
);
|
||||||
private resizeObserver: ResizeObserver | null = null;
|
private resizeObserver: ResizeObserver | null = null;
|
||||||
private animationFrame = 0;
|
private animationFrame = 0;
|
||||||
private container: HTMLElement | null = null;
|
private container: HTMLElement | null = null;
|
||||||
private brushSelectionChangeHandler: ((selection: EditorSelection) => void) | null = null;
|
private brushSelectionChangeHandler: ((selection: EditorSelection) => void) | null = null;
|
||||||
|
private createBoxBrushHandler: ((center: Vec3) => void) | null = null;
|
||||||
|
private boxCreatePreviewHandler: ((center: Vec3 | null) => void) | null = null;
|
||||||
|
private toolMode: ToolMode = "select";
|
||||||
|
private lastBoxCreatePreviewCenter: Vec3 | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.camera.position.set(10, 9, 10);
|
this.camera.position.set(10, 9, 10);
|
||||||
@@ -84,6 +114,10 @@ export class ViewportHost {
|
|||||||
this.scene.add(this.sunLight);
|
this.scene.add(this.sunLight);
|
||||||
this.scene.add(this.brushGroup);
|
this.scene.add(this.brushGroup);
|
||||||
this.scene.add(this.entityGroup);
|
this.scene.add(this.entityGroup);
|
||||||
|
this.boxCreatePreviewMesh.visible = false;
|
||||||
|
this.boxCreatePreviewEdges.visible = false;
|
||||||
|
this.scene.add(this.boxCreatePreviewMesh);
|
||||||
|
this.scene.add(this.boxCreatePreviewEdges);
|
||||||
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +125,8 @@ export class ViewportHost {
|
|||||||
this.container = container;
|
this.container = container;
|
||||||
container.appendChild(this.renderer.domElement);
|
container.appendChild(this.renderer.domElement);
|
||||||
this.renderer.domElement.addEventListener("pointerdown", this.handlePointerDown);
|
this.renderer.domElement.addEventListener("pointerdown", this.handlePointerDown);
|
||||||
|
this.renderer.domElement.addEventListener("pointermove", this.handlePointerMove);
|
||||||
|
this.renderer.domElement.addEventListener("pointerleave", this.handlePointerLeave);
|
||||||
this.resize();
|
this.resize();
|
||||||
|
|
||||||
this.resizeObserver = new ResizeObserver(() => {
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
@@ -119,6 +155,23 @@ export class ViewportHost {
|
|||||||
this.brushSelectionChangeHandler = handler;
|
this.brushSelectionChangeHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setCreateBoxBrushHandler(handler: ((center: Vec3) => void) | null) {
|
||||||
|
this.createBoxBrushHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBoxCreatePreviewHandler(handler: ((center: Vec3 | null) => void) | null) {
|
||||||
|
this.boxCreatePreviewHandler = handler;
|
||||||
|
handler?.(this.lastBoxCreatePreviewCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolMode(toolMode: ToolMode) {
|
||||||
|
this.toolMode = toolMode;
|
||||||
|
|
||||||
|
if (toolMode !== "box-create") {
|
||||||
|
this.setBoxCreatePreview(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
if (this.animationFrame !== 0) {
|
if (this.animationFrame !== 0) {
|
||||||
cancelAnimationFrame(this.animationFrame);
|
cancelAnimationFrame(this.animationFrame);
|
||||||
@@ -128,14 +181,21 @@ export class ViewportHost {
|
|||||||
this.resizeObserver?.disconnect();
|
this.resizeObserver?.disconnect();
|
||||||
this.resizeObserver = null;
|
this.resizeObserver = null;
|
||||||
this.renderer.domElement.removeEventListener("pointerdown", this.handlePointerDown);
|
this.renderer.domElement.removeEventListener("pointerdown", this.handlePointerDown);
|
||||||
|
this.renderer.domElement.removeEventListener("pointermove", this.handlePointerMove);
|
||||||
|
this.renderer.domElement.removeEventListener("pointerleave", this.handlePointerLeave);
|
||||||
this.clearBrushMeshes();
|
this.clearBrushMeshes();
|
||||||
this.clearPlayerStartMarkers();
|
this.clearPlayerStartMarkers();
|
||||||
|
this.setBoxCreatePreview(null);
|
||||||
|
|
||||||
for (const cachedTexture of this.materialTextureCache.values()) {
|
for (const cachedTexture of this.materialTextureCache.values()) {
|
||||||
cachedTexture.texture.dispose();
|
cachedTexture.texture.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.materialTextureCache.clear();
|
this.materialTextureCache.clear();
|
||||||
|
this.boxCreatePreviewMesh.geometry.dispose();
|
||||||
|
this.boxCreatePreviewMesh.material.dispose();
|
||||||
|
this.boxCreatePreviewEdges.geometry.dispose();
|
||||||
|
this.boxCreatePreviewEdges.material.dispose();
|
||||||
this.renderer.dispose();
|
this.renderer.dispose();
|
||||||
|
|
||||||
if (this.container !== null && this.container.contains(this.renderer.domElement)) {
|
if (this.container !== null && this.container.contains(this.renderer.domElement)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user