techkaczynski.dev / code

summaryrefslogtreecommitdiff
path: root/editor.c
diff options
context:
space:
mode:
Diffstat (limited to 'editor.c')
-rw-r--r--editor.c346
1 files changed, 295 insertions, 51 deletions
diff --git a/editor.c b/editor.c
index 1feb6ca..5ae5233 100644
--- a/editor.c
+++ b/editor.c
@@ -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();
}
}