-
Notifications
You must be signed in to change notification settings - Fork 0
/
editmode.js
123 lines (112 loc) · 3.54 KB
/
editmode.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { Vec2, Vec3, Mesh, GridHelper } from 'ogl';
import {makeButtonInList} from './ui.js';
const STATE = {EDIT: 0, GRAB: 1, TERRAIN_EDIT: 2, DISABLED: -1}
const PLANE = {origin: new Vec3(0, 0, 0), normal: new Vec3(0, 1, 0)}
export class EditMode {
constructor({msgBus = msgBus,
raycast = raycast,
scene = scene,
camera = camera,
renderer = renderer},
terrain) {
this.state = STATE.EDIT;
this.heldObject = null;
this.gl = renderer.gl;
this.canvas = renderer.gl.canvas;
this.msgBus = msgBus;
this.raycast = raycast;
this.scene = scene;
this.camera = camera;
this.renderer = renderer;
this.mouse = new Vec2();
this.objectList = [];
this.terrain = terrain;
this.raycast.createList("terrainCells", "BOUNDS");
for (const cell of terrain.grid) {this.raycast.addObject(cell, "terrainCells")}
this.gridHelper = new GridHelper(this.gl, {size: 100, divisions: 100});
this.gridHelper.setParent(this.scene);
this.msgBus.register("onAssetsLoaded", (assets) => {this.setupAssets(assets)});
this.registerCallbacks();
}
setupAssets(assets) {
this.assets = assets.items;
for (const assetId in this.assets) {
makeButtonInList(this.assets[assetId].name, "buttonList", (event) => {
if (this.heldObject) this.heldObject = undefined;
this.heldObject = new Mesh(this.gl, this.assets[assetId]);
this.state = STATE.GRAB;
this.heldObject.position[2] = -1000;
this.heldObject.setParent(this.scene);
});
}
makeButtonInList("Clear", "buttonList", () => {
if (this.heldObject) {
this.heldObject.setParent(null);
this.heldObject = undefined;
}
this.state = STATE.EDIT;
});
makeButtonInList("Edit Terrain", "buttonList", () => {
if (this.heldObject) {
this.heldObject.setParent(null);
this.heldObject = undefined;
}
this.state = STATE.TERRAIN_EDIT;
});
}
pointerDown(e) {
switch ( this.state ) {
case STATE.GRAB:
this.heldObjectDrop(e);
break;
case STATE.EDIT:
this.heldObjectGrab(e);
break;
case STATE.TERRAIN_EDIT:
this.terrainDestroy(e);
break;
}
}
pointerMove(e) {
if ( this.state == STATE.GRAB ) {
this.heldObjectUpdate(e);
}
}
terrainDestroy(e) {
const hits = this.raycast.intersectList(e, this.camera, "terrainCells");
if (hits[0]) {
hits[0].filled = false;
this.raycast.removeObject(hits[0], "terrainCells");
this.terrain.updateCellNeighbors(hits[0].x, hits[0].y);
}
}
heldObjectUpdate(e) {
const intersection = this.raycast.intersectPlane(e, this.camera, PLANE);
if (intersection) {
this.heldObject.position = intersection.clone();
}
}
heldObjectDrop(e) {
this.heldObjectUpdate(e);
this.state = STATE.EDIT;
this.objectList.push(this.heldObject);
this.heldObject = undefined;
}
heldObjectGrab(e) {
const hits = this.raycast.intersectMeshes(
e, this.camera, this.objectList, {includeUV: false, includeNormal: false}
);
if (hits.length) {
this.heldObject = hits[0];
const objIndex = this.objectList.indexOf(hits[0]);
if (objIndex > -1) {this.objectList.splice(objIndex, 1)}
this.state = STATE.GRAB;
}
}
registerCallbacks() {
this.canvas.addEventListener('pointerdown', (e) => this.pointerDown(e));
this.canvas.addEventListener('pointermove', (e) => this.pointerMove(e));
}
unregisterCallbacks() {
}
}