101 lines
2.3 KiB
C
101 lines
2.3 KiB
C
|
const vec3 WORLD_UP = {0.0f, 0.0f, 1.0f};
|
||
|
|
||
|
typedef struct camera {
|
||
|
vec3 position;
|
||
|
vec3 front;
|
||
|
vec3 right;
|
||
|
float yaw;
|
||
|
float pitch;
|
||
|
mat4 view_mat;
|
||
|
} camera_t;
|
||
|
|
||
|
void
|
||
|
camera_update_view(camera_t* camera)
|
||
|
{
|
||
|
// Create orthonormal basis for camera orientation
|
||
|
vec3 target = vec3_add(camera->position, camera->front);
|
||
|
vec3 front = vec3_normalize(vec3_sub(target, camera->position));
|
||
|
vec3 side = vec3_normalize(vec3_cross(front, WORLD_UP));
|
||
|
vec3 up = vec3_cross(side, front);
|
||
|
|
||
|
// Create an inverse rotation matrix
|
||
|
// Orthogonal inverse is a simple transpose where the columns become the rows
|
||
|
// +X: Right
|
||
|
// +Y: Forward
|
||
|
// +Z: Up
|
||
|
mat4 view_mat = {
|
||
|
side.x, side.y, side.z, -vec3_dot(camera->position, side),
|
||
|
up.x, up.y, up.z, -vec3_dot(camera->position, up),
|
||
|
front.x, front.y, front.z, -vec3_dot(camera->position, front),
|
||
|
0.0f, 0.0f, 0.0f, 1.0f
|
||
|
};
|
||
|
|
||
|
camera->view_mat = view_mat;
|
||
|
}
|
||
|
|
||
|
camera_t
|
||
|
camera_create(vec3 position)
|
||
|
{
|
||
|
camera_t result = {
|
||
|
.position = position,
|
||
|
.front = {0.0f, 1.0f, 0.0f},
|
||
|
.right = {1.0f, 0.0f, 0.0f},
|
||
|
.yaw = 90.0f};
|
||
|
|
||
|
camera_update_view(&result);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
camera_move(camera_t* camera, vec3 velocity)
|
||
|
{
|
||
|
// Preserve Z
|
||
|
float position_z = camera->position.z;
|
||
|
|
||
|
// Forward/Backward
|
||
|
camera->position = vec3_add(camera->position, vec3_mult(camera->front, velocity.y));
|
||
|
|
||
|
// Left/Right
|
||
|
camera->right = vec3_cross(camera->front, WORLD_UP);
|
||
|
camera->position = vec3_add(camera->position, vec3_mult(vec3_normalize(camera->right), velocity.x));
|
||
|
|
||
|
// Restore Z
|
||
|
camera->position.z = position_z;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
camera_rotate(camera_t* camera, float offset_x, float offset_y)
|
||
|
{
|
||
|
camera->yaw += offset_x;
|
||
|
camera->pitch += offset_y;
|
||
|
|
||
|
// Limit the camera's up/down motion
|
||
|
if (camera->pitch > 60.0f)
|
||
|
{
|
||
|
camera->pitch = 60.0f;
|
||
|
}
|
||
|
else if (camera->pitch < -60.0f)
|
||
|
{
|
||
|
camera->pitch = -60.0f;
|
||
|
}
|
||
|
|
||
|
// Ensure camera yaw circles around 360 degrees rather than increases indefinitely
|
||
|
if (camera->yaw > 360.0f)
|
||
|
{
|
||
|
camera->yaw -= 360.0f;
|
||
|
}
|
||
|
else if (camera->yaw < -360.0f)
|
||
|
{
|
||
|
camera->yaw += 360.0f;
|
||
|
}
|
||
|
|
||
|
float yaw_rad = DEG_TO_RAD(camera->yaw);
|
||
|
float pitch_rad = DEG_TO_RAD(camera->pitch);
|
||
|
camera->front.x = cosf(yaw_rad) * cosf(pitch_rad);
|
||
|
camera->front.y = sinf(yaw_rad) * cosf(pitch_rad);
|
||
|
camera->front.z = sinf(pitch_rad);
|
||
|
camera->front = vec3_normalize(camera->front);
|
||
|
}
|
||
|
|