techkaczynski.dev / code

summaryrefslogtreecommitdiff
path: root/cam.c
diff options
context:
space:
mode:
Diffstat (limited to 'cam.c')
-rw-r--r--cam.c198
1 files changed, 175 insertions, 23 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);
}
}