package renderer import "core:math" import "core:math/linalg" Camera :: struct { position: [3]f32, forward, up, right: [3]f32, fov_degrees: f32, near, far: f32, } create_camera :: proc(renderer: ^Renderer, position: [3]f32, forward, up: [3]f32, fov_degrees, near, far: f32) -> Camera { c: Camera c.position = position c.forward = forward c.up = up c.fov_degrees = fov_degrees c.near = near c.far = far assert(c.forward != {}) assert(c.up != {}) assert(fov_degrees > 0) assert(near > 0) assert(far > 0) return c } get_camera_view_matrix :: proc(camera: ^Camera) -> (linalg.Matrix4f32, bool) { if camera == nil { return {}, false } center := camera.position + camera.forward view_matrix := linalg.MATRIX4F32_IDENTITY view_matrix *= linalg.matrix4_look_at_f32(camera.position, center, camera.up, flip_z_axis = true) return view_matrix, true } get_camera_projection_matrix :: proc(renderer: ^Renderer, camera: ^Camera) -> (linalg.Matrix4f32, bool) { if camera == nil { return {}, false } projection_matrix := linalg.MATRIX4F32_IDENTITY projection_matrix *= linalg.matrix4_perspective( linalg.to_radians(f32(camera.fov_degrees)), get_aspect_ratio(renderer), camera.near, camera.far, flip_z_axis = true, ) return projection_matrix, true } rotate_camera :: proc(camera: ^Camera, yaw, pitch, roll: f32) { pitch := clamp(pitch, -89.0, 89.0) pitch_rad := linalg.to_radians(pitch) yaw_rad := linalg.to_radians(yaw) roll_rad := linalg.to_radians(roll) camera.forward = [3]f32{ math.cos(pitch_rad) * math.cos(yaw_rad), math.sin(pitch_rad), math.cos(pitch_rad) * math.sin(yaw_rad), } WORLD_UP :: [3]f32{0, 1, 0} camera.right = linalg.normalize(linalg.cross(camera.forward, WORLD_UP)) camera.up = linalg.normalize(linalg.cross(camera.right, camera.forward)) // TODO: SS - Support 'roll'. } set_active_camera :: proc(renderer: ^Renderer, camera: ^Camera) { renderer.active_camera = camera } get_active_camera :: proc(renderer: ^Renderer) -> ^Camera { return renderer.active_camera }