Skip to content

Commit 1664107

Browse files
committed
Gizmos working with absolute coordinates
1 parent b18f978 commit 1664107

6 files changed

Lines changed: 155 additions & 63 deletions

File tree

src/rendering/types/node.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ export class Node {
3737

3838

3939
intersects_with(line:Line){
40+
if(!this.inverse_model) return false;
41+
42+
43+
4044
const local_origin = mul_mat4_vec4(this.inverse_model,vec4(line.point[0],line.point[1],line.point[2],1.0));
4145
const local_dir = mul_mat4_vec4(this.inverse_model,vec4(line.directional_vector[0],line.directional_vector[1],line.directional_vector[2],0.0));
4246

src/rendering/utils/primitives.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ export function merge_geometries(geo1:Geometry, geo2:Geometry) : Geometry{
289289
const n_i2 = geo2.indices.length;
290290

291291
const new_indices = new IndexingType(n_i1 + n_i2);
292-
new_vertices.set(geo1.indices);
293-
new_vertices.set(geo2.vertices,n_i1);
292+
new_indices.set(geo1.indices);
293+
new_indices.set(geo2.vertices,n_i1);
294294

295295
const offset = n1 / 3;
296296
for(let i = 0; i < n_i2; ++i){

src/ui/inspector.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ export class Inspector {
108108
let dirty = false;
109109

110110
switch(e.key.toLowerCase()) {
111-
case 'w': this.current_node.position[2] -= this.move_speed; dirty = true; break; // Forward
112-
case 's': this.current_node.position[2] += this.move_speed; dirty = true; break; // Backward
113-
case 'a': this.current_node.position[0] -= this.move_speed; dirty = true; break; // Left
114-
case 'd': this.current_node.position[0] += this.move_speed; dirty = true; break; // Right
115-
case 'q': this.current_node.position[1] += this.move_speed; dirty = true; break; // Up
116-
case 'e': this.current_node.position[1] -= this.move_speed; dirty = true; break; // Down
111+
case 'w': this.current_node.position[2] -= this.move_speed; dirty = true; break;
112+
case 's': this.current_node.position[2] += this.move_speed; dirty = true; break;
113+
case 'a': this.current_node.position[0] -= this.move_speed; dirty = true; break;
114+
case 'd': this.current_node.position[0] += this.move_speed; dirty = true; break;
115+
case 'q': this.current_node.position[1] += this.move_speed; dirty = true; break;
116+
case 'e': this.current_node.position[1] -= this.move_speed; dirty = true; break;
117117
}
118118

119119
if (dirty) {

src/ui/scene_manager.ts

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ import { Viewport } from "./viewport";
1313
import { Inspector } from "./inspector";
1414
import { initialize_toolbar } from "./toolbar";
1515
import { Node } from "../rendering/types/node";
16+
import type { EditorMode } from "./state_manager";
17+
import { EditorState } from "./state_manager";
1618

1719
export class SceneManager {
1820
public scene: Scene;
1921
public nodes: Node[] = [];
2022

2123
private viewport: Viewport;
2224
private inspector: Inspector;
25+
private editor_state:EditorState
2326

2427
private target_element: HTMLElement;
2528
private wireframe_checkbox: HTMLInputElement;
@@ -29,6 +32,11 @@ export class SceneManager {
2932
private animation_id: number | null = null;
3033
public selected_node: Node | null = null;
3134

35+
private last_mx:number = 0;
36+
private last_my:number = 0;
37+
38+
private is_dragging = false;
39+
3240
public current_triangles: number = 0;
3341
public current_capacity: number = 50000;
3442
public readonly MAX_TRIANGLES: number = 100000;
@@ -53,6 +61,7 @@ export class SceneManager {
5361

5462
this.viewport = new Viewport(svg_container_id);
5563
this.inspector = new Inspector(inspector_id);
64+
this.editor_state = new EditorState(this.inspector,this.scene);
5665

5766
this.setup_lights();
5867
this.update_stats_ui();
@@ -124,7 +133,7 @@ export class SceneManager {
124133

125134
public select_node(node: Node) {
126135
this.selected_node = node;
127-
this.inspector.inspect(this.selected_node);
136+
this.editor_state.select(this.selected_node);
128137
}
129138

130139
public start() {
@@ -137,10 +146,19 @@ export class SceneManager {
137146
private loop = () => {
138147
const camera_pos = this.viewport.camera_pos;
139148
const view = this.viewport.get_view_matrix();
140-
const projection = perspective(60 * Math.PI / 180, 400 / 300, 0.1, 100);
149+
const projection = this.viewport.get_projection();
141150
const vp = mul_mat4(projection, view);
142151

143-
const models = this.nodes.map(n => n.model);
152+
this.editor_state.update_gizmo_transforms();
153+
154+
const all_nodes = [
155+
this.editor_state.gizmo_z,
156+
this.editor_state.gizmo_y,
157+
this.editor_state.gizmo_x,
158+
...this.nodes
159+
]
160+
161+
const models = all_nodes.map(n => n.model);
144162
const mvps = models.map(m => mul_mat4(vp, m));
145163

146164
for (let i = 0; i < this.scene.meshes.length; ++i) {
@@ -160,6 +178,8 @@ export class SceneManager {
160178
this.target_element.addEventListener("mousedown", (e: MouseEvent) => {
161179
if (e.button !== 0) return;
162180

181+
this.is_dragging = true;
182+
163183
const rect = this.target_element.getBoundingClientRect();
164184
const mouse_x = e.clientX - rect.left;
165185
const mouse_y = e.clientY - rect.top;
@@ -168,7 +188,7 @@ export class SceneManager {
168188
const y_ndc = 1.0 - (2.0 * mouse_y) / rect.height;
169189

170190
const view = this.viewport.get_view_matrix();
171-
const projection = perspective(60 * Math.PI / 180, 400 / 300, 0.1, 100);
191+
const projection = this.viewport.get_view_matrix();
172192
const vp = mul_mat4(projection, view);
173193
const inv_vp = inverse_mat4(vp);
174194

@@ -202,12 +222,27 @@ export class SceneManager {
202222
directional_vector: direction
203223
};
204224

205-
for (const node of this.nodes) {
206-
if (node.intersects_with(ray)) {
207-
this.select_node(node);
208-
break;
209-
}
225+
this.editor_state.handle_mouse_down(ray, e.clientX, e.clientY, this.nodes);
226+
this.selected_node = this.editor_state.selected_node;
227+
});
228+
window.addEventListener("mousemove", (e: MouseEvent) => {
229+
if (!this.is_dragging) return;
230+
231+
const dx = e.clientX - this.last_mx;
232+
const dy = e.clientY - this.last_my;
233+
234+
this.last_mx = e.clientX;
235+
this.last_my = e.clientY;
236+
237+
if (this.editor_state.mode !== "IDLE") {
238+
this.editor_state.handle_mouse_move(e.clientX, e.clientY);
239+
} else {
240+
this.viewport.orbit(dx, dy);
210241
}
211242
});
243+
window.addEventListener("mouseup", () => {
244+
this.is_dragging = false;
245+
this.editor_state.handle_mouse_up();
246+
});
212247
}
213248
}

src/ui/state_manager.ts

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,32 @@ import { vec3 } from "../math/types";
33
import type { Line } from "../math/types";
44
import { Inspector } from "./inspector";
55
import { create_arrow } from "../rendering/utils/primitives";
6-
import { Mesh } from "../rendering/types/mesh";
76
import type { Scene } from "../rendering/types/scene";
7+
import { scale } from "../math/transformations";
88

9-
export enum EditorMode {
10-
IDLE,
11-
TRANSLATE_X,
12-
TRANSLATE_Y,
13-
TRANSLATE_Z
14-
}
9+
export type EditorMode = "IDLE" | "TRANSLATE_X" | "TRANSLATE_Y" | "TRANSLATE_Z";
1510

1611
export class EditorState {
17-
public mode: EditorMode = EditorMode.IDLE;
12+
public mode: EditorMode = "IDLE";
1813
public selected_node: Node | null = null;
1914

2015
public gizmo_x!: Node;
2116
public gizmo_y!: Node;
2217
public gizmo_z!: Node;
2318

19+
private is_dragging = false;
20+
private last_x = 0;
21+
private last_y = 0;
22+
2423
private inspector: Inspector;
2524

26-
constructor(inspector: Inspector, scene:Scene) {
25+
constructor(inspector: Inspector, scene: Scene) {
2726
this.inspector = inspector;
2827
this.setup_gizmos(scene);
28+
this.select(null);
2929
}
3030

31-
private setup_gizmos(scene:Scene) {
31+
private setup_gizmos(scene: Scene) {
3232
const arrow_geo = create_arrow();
3333

3434
const mesh_z = scene.add_mesh(arrow_geo, vec3(0, 0, 1), 0);
@@ -45,16 +45,34 @@ export class EditorState {
4545
this.gizmo_x.update_matrix();
4646
this.gizmo_y.update_matrix();
4747
this.gizmo_z.update_matrix();
48-
}
48+
}
4949

5050
public select(node: Node | null) {
5151
this.selected_node = node;
5252
this.inspector.inspect(node);
53-
this.update_gizmo_transforms();
53+
54+
if (node) {
55+
const scale_amount = node.scale_vec;
56+
this.gizmo_x.scale_vec = scale_amount;
57+
this.gizmo_y.scale_vec = scale_amount;
58+
this.gizmo_z.scale_vec = scale_amount;
59+
this.update_gizmo_transforms();
60+
} else {
61+
this.gizmo_x.scale_vec = vec3(0, 0, 0);
62+
this.gizmo_y.scale_vec = vec3(0, 0, 0);
63+
this.gizmo_z.scale_vec = vec3(0, 0, 0);
64+
this.update_gizmo_transforms();
65+
}
5466
}
5567

5668
public update_gizmo_transforms() {
57-
if (!this.selected_node) return;
69+
if (!this.selected_node) {
70+
this.gizmo_x.update_matrix();
71+
this.gizmo_y.update_matrix();
72+
this.gizmo_z.update_matrix();
73+
return;
74+
}
75+
5876
const pos = this.selected_node.position;
5977

6078
this.gizmo_x.position = vec3(pos[0], pos[1], pos[2]);
@@ -66,42 +84,64 @@ export class EditorState {
6684
this.gizmo_z.update_matrix();
6785
}
6886

69-
public process_raycast(ray: Line, scene_nodes: Node[]) {
87+
public handle_mouse_down(ray: Line, mouse_x: number, mouse_y: number, scene_nodes: Node[]) {
88+
this.is_dragging = true;
89+
this.last_x = mouse_x;
90+
this.last_y = mouse_y;
91+
7092
if (this.selected_node) {
7193
if (this.gizmo_x.intersects_with(ray)) {
72-
this.mode = EditorMode.TRANSLATE_X;
94+
this.mode = "TRANSLATE_X";
7395
return;
7496
}
7597
if (this.gizmo_y.intersects_with(ray)) {
76-
this.mode = EditorMode.TRANSLATE_Y;
98+
this.mode = "TRANSLATE_Y";
7799
return;
78100
}
79101
if (this.gizmo_z.intersects_with(ray)) {
80-
this.mode = EditorMode.TRANSLATE_Z;
102+
this.mode = "TRANSLATE_Z";
81103
return;
82104
}
83105
}
84-
85106
for (const node of scene_nodes) {
86107
if (node.intersects_with(ray)) {
87108
this.select(node);
88109
return;
89110
}
90111
}
91-
92112
this.select(null);
93113
}
94114

95-
public process_drag(dx: number, dy: number) {
96-
if (!this.selected_node || this.mode === EditorMode.IDLE) return;
115+
public handle_mouse_move(mouse_x: number, mouse_y: number) {
116+
if (!this.is_dragging) return;
97117

98-
console.log(`Dragging mode: ${this.mode}, Delta: ${dx}, ${dy}`);
118+
const dx = mouse_x - this.last_x;
119+
const dy = mouse_y - this.last_y;
99120

121+
this.last_x = mouse_x;
122+
this.last_y = mouse_y;
123+
124+
if (!this.selected_node || this.mode === "IDLE") return;
125+
126+
const sensitivity = 0.02;
127+
128+
if (this.mode === "TRANSLATE_X") {
129+
this.selected_node.position[0] += dx * sensitivity;
130+
} else if (this.mode === "TRANSLATE_Y") {
131+
this.selected_node.position[1] -= dy * sensitivity;
132+
} else if (this.mode === "TRANSLATE_Z") {
133+
this.selected_node.position[2] -= (dx + dy) * sensitivity;
134+
}
135+
136+
this.selected_node.update_matrix();
100137
this.update_gizmo_transforms();
138+
139+
this.inspector.inspect(this.selected_node);
101140
}
102141

103-
public release_drag() {
104-
this.mode = EditorMode.IDLE;
142+
public handle_mouse_up() {
143+
this.is_dragging = false;
144+
this.mode = "IDLE";
105145
}
106146

107147
public get_active_gizmos(): Node[] {

0 commit comments

Comments
 (0)