diff options
Diffstat (limited to 'editor.c')
| -rw-r--r-- | editor.c | 346 |
1 files changed, 295 insertions, 51 deletions
@@ -508,6 +508,8 @@ editor_init(void) { ed.history_save_csr = save_file_read("res/save/scene.fgs") ? ed.history_csr : UINT32_MAX; + + ed.grid_sz = 1.0f; } void @@ -706,7 +708,7 @@ case ED_INTERACT_NONE: /* scale */ } - if (IsKeyPressed(KEY_X)) { + if (IsKeyPressed(KEY_DELETE)) { if (!ctrl && ed.sel_cnt) { EditorAction action = action_begin(ED_ACTION_DELETE, true); if (action.item_cnt) { @@ -779,8 +781,6 @@ default: !ed.focus_captured && !ed.panel[ED_PNL_CENTER].enabled); - cam_update(); - /* reset selection data */ ed.sel_cnt = 0; ed.sel_point = Vector3Zero(); @@ -807,6 +807,9 @@ default: if (ed.sel_cnt != 1) { ed.sel_rot = QuaternionIdentity(); } + + main_cam.view_rotation = ed.sel_rot; + cam_update(); } /* tools */ @@ -1027,11 +1030,26 @@ ray_plane_hit(Vec3 plane_pos, Vec3 plane_dir, Vec3 *out) { void editor_move(void) { - static Vec3 mv_start = {0}; + static Vec3 mv_start; + static Vec3 previous_axis; + static bool previous_plane; + static Vec3 raw_pivot; + static bool previous_local; if (!tr_action.item) { tr_action = action_begin(ED_ACTION_TRANSFORM, true); - started = false; + mv_start = selected_pivot(); + + raw_pivot = mv_start; + ed.move_snap_origin = mv_start; + previous_local = false; + started = true; + + ed.move_rotation = ed.sel_rot; + ed.move_axis = -1; + ed.move_plane = true; + previous_axis = (Vec3){0, 1, 0}; + previous_plane = true; } bool cancel = IsKeyPressed(KEY_ESCAPE) || !tr_action.item_cnt; @@ -1049,29 +1067,84 @@ editor_move(void) { return; } - Vec3 pivot = selected_pivot(); - Vec3 axis = { 0, 1, 0 }; // mv plane normal - Vec3 delta = {0}; + if (IsKeyDown(KEY_LEFT_CONTROL)) { + f32 wheel = GetMouseWheelMove(); - if (IsKeyDown(KEY_LEFT_ALT)) { - started = false; + if (wheel != 0) { + ed.grid_sz = Clamp( + ed.grid_sz * powf(2.0f, wheel), + 0.125f, 64.0f); + } + } - Vec2 a = GetWorldToScreen(pivot, main_cam.cam); - Vec2 b = GetWorldToScreen( - Vector3Add(pivot, axis), main_cam.cam); + if (IsKeyPressed(KEY_L)) { + main_cam.local_space = !main_cam.local_space; + } - Vec2 scr_axis = Vector2Subtract(b, a); - f32 lensqr = Vector2LengthSqr(scr_axis); + bool local = main_cam.local_space && ed.sel_cnt == 1; + int keys[3] = {KEY_X, KEY_Y, KEY_Z}; - if (lensqr <= 0.001f) { - return; + for (int i = 0; i < 3; ++i) { + if (!IsKeyPressed(keys[i])) { + continue; } - f32 amount = - Vector2DotProduct(GetMouseDelta(), scr_axis) / lensqr; + bool plane = IsKeyDown(KEY_LEFT_SHIFT); - delta = Vector3Scale(axis, amount); - } else { + if (ed.move_axis == i && ed.move_plane == plane) { + ed.move_axis = -1; + ed.move_plane = true; + } else { + ed.move_axis = i; + ed.move_plane = plane; + } + } + + /* Global XZ is simply the default floor plane. */ + if (!local && ed.move_axis == 1 && ed.move_plane) { + ed.move_axis = -1; + } + + Vec3 axes[3] = { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }; + Vec3 axis = {0, 1, 0}; + bool plane = true; + + if (ed.move_axis >= 0) { + axis = axes[ed.move_axis]; + plane = ed.move_plane; + + if (local) { + axis = Vector3RotateByQuaternion(axis, + ed.move_rotation); + } + } + + if (IsKeyDown(KEY_LEFT_ALT)) { + axis = (Vec3){0, 1, 0}; + plane = false; + } + + bool use_local = local && ed.move_axis >= 0 && + !IsKeyDown(KEY_LEFT_ALT); + + if (!Vector3Equals(axis, previous_axis) || + plane != previous_plane || use_local != previous_local) { + previous_axis = axis; + previous_plane = plane; + previous_local = use_local; + raw_pivot = selected_pivot(); + ed.move_snap_origin = raw_pivot; + started = false; + } + + Vec3 pivot = selected_pivot(); + Vec3 delta = {0}; + + if (plane) { Vec3 hit; if (!ray_plane_hit(pivot, axis, &hit)) { return; @@ -1085,8 +1158,68 @@ editor_move(void) { delta = Vector3Subtract(hit, mv_start); mv_start = hit; + } else { + if (!started) { + started = true; + return; + } + + Vec2 a = GetWorldToScreen(pivot, main_cam.cam); + Vec2 b = GetWorldToScreen( + Vector3Add(pivot, axis), main_cam.cam); + Vec2 screen_axis = Vector2Subtract(b, a); + f32 length_squared = Vector2LengthSqr(screen_axis); + + if (length_squared <= 0.001f) { + return; + } + + f32 amount = Vector2DotProduct( + GetMouseDelta(), screen_axis) / length_squared; + delta = Vector3Scale(axis, amount); + } + + raw_pivot = Vector3Add(raw_pivot, delta); + Vec3 destination = raw_pivot; + + if (IsKeyDown(KEY_LEFT_CONTROL) && ed.grid_sz > 0) { + int constrained_axis = ed.move_axis >= 0 ? ed.move_axis : 1; + + if (IsKeyDown(KEY_LEFT_ALT)) { + constrained_axis = 1; + } + + Vec3 origin = use_local ? ed.move_snap_origin : Vector3Zero(); + + for (int i = 0; i < 3; ++i) { + bool enabled = plane ? + i != constrained_axis : + i == constrained_axis; + + if (!enabled) { + continue; + } + + Vec3 direction = axes[i]; + if (use_local) { + direction = Vector3RotateByQuaternion( + direction, ed.move_rotation); + } + + f32 coordinate = Vector3DotProduct( + Vector3Subtract(raw_pivot, origin), + direction); + f32 snapped = roundf(coordinate / ed.grid_sz) * + ed.grid_sz; + + destination = Vector3Add(destination, + Vector3Scale(direction, snapped - + coordinate)); + } } + delta = Vector3Subtract(destination, pivot); + for (u32 i = 0; i < tr_action.item_cnt; ++i) { u64 id = entity_id_from_pid(tr_action.item[i].pid); Entity *ent = entity_get(id); @@ -1152,18 +1285,18 @@ statusline(void) { // Color bg = { 255, 255, 255, 150 }; Color bg = GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)); + cstr view_space = "Global"; + if (main_cam.local_space) { + view_space = ed.sel_cnt == 1 ? "Local" : "Local (fallback)"; + } + switch (ed.interact) { case ED_INTERACT_NONE: - snprintf(mode_str, 16, "EDITOR"); - if (ed.sel_cnt > 0) { - snprintf(ctx_str, sizeof(ctx_str), - "%i Selected | " - "G: move, R: rotate, D: duplicate, " - "X: delete", - ed.sel_cnt); - } else { - snprintf(ctx_str, sizeof(ctx_str), "Nothing selected"); - } + snprintf(mode_str, sizeof(mode_str), "EDITOR"); + snprintf(ctx_str, sizeof(ctx_str), + "%i selected | View: %s [L] | " + "F: focus, XYZ: axis, P: projection, Del: delete", + ed.sel_cnt, view_space); break; case ED_INTERACT_SELECT: @@ -1176,20 +1309,34 @@ statusline(void) { "shift: boost speed, scroll: adjust speed"); break; - case ED_INTERACT_MOVE: - snprintf(mode_str, 16, "MOVE"); + case ED_INTERACT_MOVE: { + snprintf(mode_str, sizeof(mode_str), "MOVE"); + + cstr axes[3] = {"X", "Y", "Z"}; + cstr planes[3] = {"YZ", "XZ", "XY"}; + cstr constraint = "XZ"; + bool local = main_cam.local_space && + ed.sel_cnt == 1 && ed.move_axis >= 0; - cstr axis_str = IsKeyDown(KEY_LEFT_ALT) ? - "up axis" : - "xz plane"; + if (ed.move_axis >= 0) { + constraint = ed.move_plane ? + planes[ed.move_axis] : axes[ed.move_axis]; + } + + if (IsKeyDown(KEY_LEFT_ALT)) { + constraint = "Y"; + local = false; + } snprintf(ctx_str, sizeof(ctx_str), - "%i Selected | " - "current axis: %s | " - "controls: shift: grid snap, " - "alt: up axis, X/Y/Z: toggle axis", - ed.sel_cnt, axis_str); + "%i selected | %s %s | Snap: %.3g %s | " + "Ctrl+wheel: grid, L: space, XYZ: axis, " + "Shift+XYZ: plane", + ed.sel_cnt, local ? "Local" : "Global", constraint, + ed.grid_sz, + IsKeyDown(KEY_LEFT_CONTROL) ? "[on]" : "[off]"); break; + } case ED_INTERACT_ROTATE: snprintf(mode_str, 16, "ROTATE"); @@ -1220,7 +1367,8 @@ statusline(void) { "%s | MMB: pan, scroll: zoom", name); } else { snprintf(ctx_str, sizeof(ctx_str), - "%s | RMB: orbit, scroll: zoom", name); + "%s | View: %s [L] | RMB: orbit, scroll: zoom", + name, view_space); } } @@ -3376,18 +3524,114 @@ gizmo_transform(void) { static void gizmo_move(void) { - Color col = { 255, 255, 255, 150 }; - Vec3 point = ed.sel_point; + Vec3 pivot = ed.sel_point; + Vec3 axes[3] = { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }; + Color colors[3] = {RED, GREEN, BLUE}; + + int axis = ed.move_axis >= 0 ? ed.move_axis : 1; + bool plane = ed.move_axis < 0 || ed.move_plane; + bool local = main_cam.local_space && + ed.sel_cnt == 1 && ed.move_axis >= 0; if (IsKeyDown(KEY_LEFT_ALT)) { - DrawLine3D(point, Vector3Add(point, (Vec3){0,100,0}), col); // GREEN - DrawLine3D(point, Vector3Add(point, (Vec3){0,-100,0}), col); + axis = 1; + plane = false; + local = false; + } + + if (local) { + for (int i = 0; i < 3; ++i) { + axes[i] = Vector3RotateByQuaternion( + axes[i], ed.move_rotation); + } + } + + for (int i = 0; i < 3; ++i) { + bool enabled = plane ? i != axis : i == axis; + if (!enabled) { + continue; + } + + Vec3 extent = Vector3Scale(axes[i], 100.0f); + + DrawLine3D( + Vector3Subtract(pivot, extent), + Vector3Add(pivot, extent), + Fade(colors[i], 0.7f)); + } + + if (!IsKeyDown(KEY_LEFT_CONTROL) || ed.grid_sz <= 0) { + return; + } + + f32 step = ed.grid_sz; + Vec3 origin = local ? ed.move_snap_origin : Vector3Zero(); + Vec3 center = pivot; + + /* Align the grid center along the permitted movement axes. */ + for (int i = 0; i < 3; ++i) { + bool enabled = plane ? i != axis : i == axis; + if (!enabled) { + continue; + } + + f32 coordinate = Vector3DotProduct( + Vector3Subtract(pivot, origin), axes[i]); + f32 snapped = roundf(coordinate / step) * step; + + center = Vector3Add(center, + Vector3Scale(axes[i], snapped - coordinate)); + } + + const int count = 10; + + if (plane) { + Vec3 u = axes[(axis + 1) % 3]; + Vec3 v = axes[(axis + 2) % 3]; + Vec3 extent_u = Vector3Scale(u, count * step); + Vec3 extent_v = Vector3Scale(v, count * step); + Color color = Fade(LIGHTGRAY, 0.5f); + + for (int i = -count; i <= count; ++i) { + Vec3 along_u = Vector3Add( + center, Vector3Scale(u, i * step)); + Vec3 along_v = Vector3Add( + center, Vector3Scale(v, i * step)); + + DrawLine3D( + Vector3Subtract(along_u, extent_v), + Vector3Add(along_u, extent_v), color); + + DrawLine3D( + Vector3Subtract(along_v, extent_u), + Vector3Add(along_v, extent_u), color); + } } else { - DrawLine3D(point, Vector3Add(point, (Vec3){100,0,0}), col); //RED - DrawLine3D(point, Vector3Add(point, (Vec3){-100,0,0}), col); + /* Orient ticks across the axis, facing the camera. */ + Vec3 forward = Vector3Normalize(Vector3Subtract( + main_cam.cam.target, main_cam.cam.position)); + Vec3 tick = Vector3CrossProduct(axes[axis], forward); + + if (Vector3LengthSqr(tick) < 0.000001f) { + tick = axes[(axis + 1) % 3]; + } + + tick = Vector3Scale(Vector3Normalize(tick), step * 0.15f); - DrawLine3D(point, Vector3Add(point, (Vec3){0,0,100}), col); //BLUE - DrawLine3D(point, Vector3Add(point, (Vec3){0,0,-100}), col); + for (int i = -count; i <= count; ++i) { + Vec3 point = Vector3Add( + center, Vector3Scale(axes[axis], i * step)); + Color color = i == 0 ? + WHITE : Fade(colors[axis], 0.7f); + + DrawLine3D( + Vector3Subtract(point, tick), + Vector3Add(point, tick), color); + } } } @@ -3576,7 +3820,7 @@ editor_draw_3d(void) { gizmo_rotate(); } - if (ed.sel_cnt > 0) { + if (ed.sel_cnt > 0 && ed.interact != ED_INTERACT_MOVE) { gizmo_transform(); } } |
