techkaczynski.dev / code

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cam.c198
-rw-r--r--cam.h5
-rw-r--r--editor.c346
-rw-r--r--editor.h6
4 files changed, 480 insertions, 75 deletions
diff --git a/cam.c b/cam.c
index 4576f93..6827709 100644
--- a/cam.c
+++ b/cam.c
@@ -21,6 +21,7 @@ cam_init(void) {
main_cam.allow_fly = true;
main_cam.state = CAM_MODE_EDIT_FLY;
main_cam.perspective_fov = main_cam.cam.fovy;
+ main_cam.view_rotation = QuaternionIdentity();
main_cam.mv_speed = 10;
main_cam.mv_scale = 1;
main_cam.lk_speed = 0.003f;
@@ -32,6 +33,15 @@ cam_focus(Vec3 target, f32 distance, f32 view_height) {
Vec3 backward = Vector3Normalize(
Vector3Subtract(cam->position, cam->target));
+ Quaternion rotation = QuaternionNormalize(
+ QuaternionFromMatrix(MatrixTranspose(MatrixLookAt(
+ Vector3Zero(),
+ Vector3Negate(backward),
+ cam->up))));
+
+ main_cam.transition.start_rot = rotation;
+ main_cam.transition.end_rot = rotation;
+
main_cam.transition.start_pos = cam->position;
main_cam.transition.start_target = cam->target;
@@ -51,11 +61,91 @@ cam_focus(Vec3 target, f32 distance, f32 view_height) {
main_cam.state = CAM_MODE_EDIT_ORBIT;
}
+static void
+cam_axis_view(int axis, bool negative) {
+ Camera *cam = &main_cam.cam;
+ f32 side = negative ? -1.0f : 1.0f;
+
+ Vec3 backward = {0};
+ Vec3 up = {0, 1, 0};
+
+ switch (axis) {
+ case 0:
+ backward.x = side;
+ break;
+
+ case 1:
+ backward.y = side;
+ up = (Vec3){0, 0, -side};
+ break;
+
+ case 2:
+ backward.z = side;
+ break;
+ }
+
+ if (main_cam.local_space) {
+ backward = Vector3RotateByQuaternion(
+ backward, main_cam.view_rotation);
+ up = Vector3RotateByQuaternion(
+ up, main_cam.view_rotation);
+ }
+
+ f32 distance = Vector3Distance(cam->position, cam->target);
+
+ if (cam->projection == CAMERA_PERSPECTIVE) {
+ main_cam.perspective_fov = cam->fovy;
+ cam->fovy = 2.0f * distance *
+ tanf(main_cam.perspective_fov * DEG2RAD * 0.5f);
+ cam->projection = CAMERA_ORTHOGRAPHIC;
+ }
+
+ cam_focus(cam->target, distance, cam->fovy);
+
+ main_cam.transition.end_pos = Vector3Add(
+ cam->target, Vector3Scale(backward, distance));
+
+ Matrix view = MatrixLookAt(
+ Vector3Zero(), Vector3Negate(backward), up);
+
+ main_cam.transition.end_rot = QuaternionNormalize(
+ QuaternionFromMatrix(MatrixTranspose(view)));
+
+ main_cam.axis_view = true;
+}
+
void
cam_update(void) {
if (main_cam.input) {
- if (!main_cam.update && !main_cam.transition.active &&
- IsKeyPressed(KEY_P)) {
+ bool fly = main_cam.update &&
+ main_cam.allow_fly &&
+ IsMouseButtonDown(MOUSE_BUTTON_RIGHT) &&
+ (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) ||
+ IsKeyDown(KEY_S) || IsKeyDown(KEY_D) ||
+ IsKeyDown(KEY_Q) || IsKeyDown(KEY_E));
+
+ if (fly) {
+ main_cam.transition.active = false;
+ main_cam.state = CAM_MODE_EDIT_FLY;
+ }
+
+ Vec2 mouse = GetMouseDelta();
+ bool rotate = main_cam.update &&
+ IsMouseButtonDown(MOUSE_BUTTON_RIGHT) &&
+ !IsMouseButtonDown(MOUSE_BUTTON_MIDDLE) &&
+ (mouse.x != 0 || mouse.y != 0);
+
+ bool toggle = !main_cam.update &&
+ !main_cam.transition.active &&
+ IsKeyPressed(KEY_P);
+
+ bool leave_axis = main_cam.axis_view &&
+ !main_cam.transition.active &&
+ (fly || rotate);
+
+ if (toggle || leave_axis) {
+ main_cam.axis_view = false;
+
Camera *cam = &main_cam.cam;
f32 distance = Vector3Distance(
cam->position, cam->target);
@@ -75,8 +165,8 @@ cam_update(void) {
cam->target));
distance = cam->fovy / (2.0f *
- tanf(main_cam.perspective_fov *
- DEG2RAD * 0.5f));
+ tanf(main_cam.perspective_fov *
+ DEG2RAD * 0.5f));
cam->position = Vector3Add(
cam->target,
@@ -88,16 +178,21 @@ cam_update(void) {
}
}
- bool fly = main_cam.update &&
- main_cam.allow_fly &&
- IsMouseButtonDown(MOUSE_BUTTON_RIGHT) &&
- (IsKeyDown(KEY_W) || IsKeyDown(KEY_A) ||
- IsKeyDown(KEY_S) || IsKeyDown(KEY_D) ||
- IsKeyDown(KEY_Q) || IsKeyDown(KEY_E));
+ if (!main_cam.update && !main_cam.transition.active &&
+ !IsKeyDown(KEY_LEFT_CONTROL)) {
+ if (IsKeyPressed(KEY_L)) {
+ main_cam.local_space = !main_cam.local_space;
+ }
- if (fly) {
- main_cam.transition.active = false;
- main_cam.state = CAM_MODE_EDIT_FLY;
+ bool negative = IsKeyDown(KEY_LEFT_SHIFT);
+
+ if (IsKeyPressed(KEY_X)) {
+ cam_axis_view(0, negative);
+ } else if (IsKeyPressed(KEY_Y)) {
+ cam_axis_view(1, negative);
+ } else if (IsKeyPressed(KEY_Z)) {
+ cam_axis_view(2, negative);
+ }
}
bool navigate = main_cam.update ||
@@ -131,14 +226,29 @@ cam_update(void) {
f32 t = EaseSineInOut(
main_cam.transition.elapsed, 0.0f, 1.0f, duration);
- main_cam.cam.position = Vector3Lerp(
+ Quaternion rotation = QuaternionSlerp(
+ main_cam.transition.start_rot,
+ main_cam.transition.end_rot, t);
+
+ f32 start_distance = Vector3Distance(
main_cam.transition.start_pos,
- main_cam.transition.end_pos, t);
+ main_cam.transition.start_target);
+ f32 end_distance = Vector3Distance(
+ main_cam.transition.end_pos,
+ main_cam.transition.end_target);
+ f32 distance = Lerp(start_distance, end_distance, t);
main_cam.cam.target = Vector3Lerp(
main_cam.transition.start_target,
main_cam.transition.end_target, t);
+ Vec3 backward = Vector3RotateByQuaternion(
+ (Vec3){0, 0, 1}, rotation);
+ main_cam.cam.position = Vector3Add(
+ main_cam.cam.target, Vector3Scale(backward, distance));
+ main_cam.cam.up = Vector3RotateByQuaternion(
+ (Vec3){0, 1, 0}, rotation);
+
main_cam.cam.fovy = Lerp(
main_cam.transition.start_fovy,
main_cam.transition.end_fovy, t);
@@ -146,20 +256,68 @@ cam_update(void) {
if (main_cam.transition.elapsed >= duration) {
main_cam.cam.position = main_cam.transition.end_pos;
main_cam.cam.target = main_cam.transition.end_target;
+ main_cam.cam.up = Vector3RotateByQuaternion(
+ (Vec3){0, 1, 0}, main_cam.transition.end_rot);
main_cam.cam.fovy = main_cam.transition.end_fovy;
main_cam.transition.active = false;
}
}
static void
+cam_rotate(bool orbit) {
+ Camera *cam = &main_cam.cam;
+ Vec2 delta = GetMouseDelta();
+
+ if (orbit && delta.x == 0 && delta.y == 0) {
+ return;
+ }
+
+ Vec3 offset = Vector3Subtract(cam->position, cam->target);
+ f32 distance = Vector3Length(offset);
+ Vec3 backward = Vector3Scale(offset, 1.0f / distance);
+
+ f32 yaw = atan2f(backward.x, backward.z);
+ f32 pitch = asinf(Clamp(backward.y, -1.0f, 1.0f));
+
+ /* At a pole, use screen-up to recover the heading. */
+ if (backward.x * backward.x +
+ backward.z * backward.z < 0.000001f) {
+ f32 side = backward.y > 0 ? -1.0f : 1.0f;
+ yaw = atan2f(cam->up.x * side, cam->up.z * side);
+ }
+
+ yaw -= delta.x * main_cam.lk_speed;
+ pitch += delta.y * main_cam.lk_speed;
+ pitch = Clamp(pitch, -PI * 0.5f + 0.001f,
+ PI * 0.5f - 0.001f);
+
+ backward = (Vec3){
+ sinf(yaw) * cosf(pitch),
+ sinf(pitch),
+ cosf(yaw) * cosf(pitch),
+ };
+
+ offset = Vector3Scale(backward, distance);
+
+ if (orbit) {
+ cam->position = Vector3Add(cam->target, offset);
+ } else {
+ cam->target = Vector3Subtract(cam->position, offset);
+ }
+
+ cam->up = (Vec3){0, 1, 0};
+}
+
+static void
cam_ctrl_editor(void) {
if (!main_cam.update) {
return;
}
+ cam_rotate(false);
+
Vec3 input_dir = {0};
f32 mv_speed = main_cam.mv_speed;
- f32 lk_speed = main_cam.lk_speed;
if (IsKeyDown(KEY_W)) {
input_dir.z += 1;
@@ -211,10 +369,6 @@ cam_ctrl_editor(void) {
false);
CameraMoveUp(&main_cam.cam, input_dir.y * mv_speed * GetFrameTime());
-
- Vec2 delta = GetMouseDelta();
- CameraYaw(&main_cam.cam, -delta.x * lk_speed, false);
- CameraPitch(&main_cam.cam, -delta.y * lk_speed, true, false, false);
}
static void
@@ -264,8 +418,6 @@ cam_ctrl_orbit(void) {
cam->position = Vector3Add(cam->position, offset);
cam->target = Vector3Add(cam->target, offset);
} else {
- CameraYaw(cam, -delta.x * main_cam.lk_speed, true);
- CameraPitch(cam, -delta.y * main_cam.lk_speed,
- true, true, false);
+ cam_rotate(true);
}
}
diff --git a/cam.h b/cam.h
index 8af2614..186d3f9 100644
--- a/cam.h
+++ b/cam.h
@@ -14,11 +14,14 @@ typedef struct {
CamState state;
f32 mv_speed, mv_scale, lk_speed;
f32 perspective_fov;
- bool update, input, allow_fly;
+ bool update, input, allow_fly, axis_view;
+ bool local_space;
+ Quaternion view_rotation;
struct {
Vec3 start_pos, start_target;
Vec3 end_pos, end_target;
+ Quaternion start_rot, end_rot;
f32 start_fovy, end_fovy;
f32 elapsed;
bool active;
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();
}
}
diff --git a/editor.h b/editor.h
index 808a1ee..78a8850 100644
--- a/editor.h
+++ b/editor.h
@@ -93,6 +93,12 @@ typedef struct {
EditorInteraction interact;
EditorPanelContainer focus;
bool focus_captured;
+
+ int move_axis;
+ bool move_plane;
+ Vec3 move_snap_origin;
+ Quaternion move_rotation;
+
struct {
EditorPanelType type;
Rect bounds;